你爲什麼認爲有一個保留週期? Fetcher
不存儲傳入的completion
參考。如果您運行在操場下面:
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
class Fetcher {
func fetch(completion: [String] ->()) {
dispatch_async(dispatch_get_main_queue()) {
print("fetching")
completion([])
}
}
deinit { print("deinit Fetcher") }
}
class ViewController: UIViewController {
let fetcher = Fetcher()
func fetch() {
fetcher.fetch(didFetch)
}
func didFetch(result: [String]) {
print("did fetch")
}
deinit { print("deinit ViewController") }
}
var vc: ViewController? = ViewController()
vc?.fetch()
vc = nil
...你會看到所有的打印,因爲它應該:
fetching
did fetch
deinit ViewController
deinit Fetcher
不過,是你存放出於某種原因參考:
class Fetcher {
var completion: ([String] ->())?
func fetch(completion: [String] ->()) {
self.completion = completion // causing retain cycle
completion([])
}
}
然後你就確實有保留週期和兩個對象永遠不會deinit
...
編輯
這個問題越來越多了。特別是,由於@noescape
在我們進入異步執行過程中目前無法執行,因此我們可以接近這樣一個理想嗎?有兩種方法可以讓人想起,但這兩種方法都不幸地爲調用者提供了編譯器支持的保證,儘管它們仍然遵循原始問題的精神,因爲它們不涉及傳遞閉包:
protocol CompletionHandler : AnyObject { // only needed for `fetch2`
associatedtype Result
func onCompletion(_: Result)
}
extension Fetcher {
func fetch2 <H: CompletionHandler where H.Result == [String]> (handler: H) {
dispatch_async(dispatch_get_main_queue()) { [weak handler] in
print("fetching2")
handler?.onCompletion([])
}
}
func fetch3 <T: AnyObject> (handler: T, curry: T -> [String] ->()) {
dispatch_async(dispatch_get_main_queue()) { [weak handler] in
print("fetching3")
if let handler = handler {
curry(handler)([])
}
}
}
}
...能夠像這樣被使用(其中fetch2
假定符合CompletionHandler
):
fetcher.fetch2(self)
fetcher.fetch3(self, curry: ViewController.onCompletion)
...與效果:
var vc: ViewController? = ViewController()
vc?.fetch()
vc = nil
...印刷:
deinit ViewController
deinit Fetcher
fetching2
fetching3
(與上面的第一個解決方案的控制檯輸出,看看在下面的意見與@Sulthan討論)
也許你能刪除你的標題中提到的「令行禁止功能」 S,因爲在沒有人提這個問題? – milos