Neden bir tutma döngüsü olduğunu düşünüyorsunuz? Fetcher
, completion
başvurusunda geçirilen iletiyi saklamıyor. Eğer çalıştırırsanız bir oyun alanında aşağıdaki:
fetching
did fetch
deinit ViewController
deinit Fetcher
Ancak nedense referans olarak saklamak için senin yerinde: olması gerektiği gibi
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
... her şeyi baskılar göreceksiniz
class Fetcher {
var completion: ([String] ->())?
func fetch(completion: [String] ->()) {
self.completion = completion // causing retain cycle
completion([])
}
}
Sonra gerçekten bir döngü tutmak zorunda kalacak ve suçlu iki nesnenin would never deinit
...
Edit
Bu soru benden büyüyor. Özellikle, @noescape
'un zaman uyumsuz yürütmeye geçtiğimizden bu yana uygulamak imkansız olduğu için, böyle bir ideale ne kadar yaklaşabiliriz? Aklıma gelen iki yaklaşım vardır; ne yazık ki, ne yazık ki, derhal, asıl sorunun ruhu içinde bir kapamada geçmeyi gerektirmedikleri halde, derhal, derleyiciye destekli garantiler sunmaktadır:
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)([])
}
}
}
}
böylece gibi kullanılabilir
... (fetch2
CompletionHandler
uygunluğunu kabul olduğu):
fetcher.fetch2(self)
fetcher.fetch3(self, curry: ViewController.onCompletion)
... etkisiyle:
var vc: ViewController? = ViewController()
vc?.fetch()
vc = nil
... yazdırma:
deinit ViewController
deinit Fetcher
fetching2
fetching3
(yukarıdaki birinci çözümün konsol çıkışına karşılaştırarak aşağıdaki yorum @Sulthan ile tartışmaya bakınız) Eğer bir için bir yöntem geçmek istiyorsanız
Belki size başlığında referans için "curried işlev" ler kaldırabilirsiniz soru? – milos