[英]Correct placement of capture list in nested closures in swift
我在哪里定義Swift中嵌套閉包的捕獲引用?
以此代碼為例:
import Foundation
class ExampleDataSource {
var content: Any?
func loadContent() {
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
// completion handler called on background thread
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
/*
Load content from web asynchronously,
and call completion handler on background thread.
*/
}
}
在這個例子中, [weak self]
用在兩個尾隨閉包中,但是如果我從任何一個尾隨閉包中省略[weak self]
,編譯器會非常高興。
因此,我有3個選項來定義我的捕獲列表:
我的問題是:
如果我知道我的
ExampleDataSource
在某些時候可能是nil
,那么最好的選擇是什么?
值得注意的是,GCD dispatch_async不會導致保留周期。 換句話說,當塊完成執行時,GCD將不保留塊內的任何引用。
對於類之間的強引用或分配給實例屬性的閉包內的強引用,情況也是如此。 Apple文檔
話雖如此,在這個例子中,正確答案是選項2,僅在第一個閉包上定義捕獲。
出於測試目的,我稍微修改了代碼:
class ExampleDataSource {
init() {
print("init()")
}
deinit {
print("deinit")
}
var content: Any?
func loadContent() {
print("loadContent()")
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
dispatch_async(dispatch_get_main_queue()) {
print("loadedContent")
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
sleep(5) // thread will hang for 5 seconds
completion(loadedContent: "some data")
}
}
}
首先我創建了var myDataSource: ExampleDataSource? = ExampleDataSource()
var myDataSource: ExampleDataSource? = ExampleDataSource()
。
然后我運行myDataSource.loadContent()
。
在完成處理程序有機會運行之前,我設置myDataSource = nil
,刪除對它的所有引用。
調試控制台指示未保留對self的引用:
init()
loadContent()
deinit
loadedContent
看起來我們找到了答案! 但為了完成,讓我們測試替代方案......
如果僅在最內部的尾隨閉包上捕獲[weak self]
,則GCD將保留ExampleDataSource
直到塊完成執行,這解釋了為什么調試將如下所示:
init()
loadContent()
loadedContent
deinit
如果沒有包含捕獲列表,我們也永遠不會打開self
,雖然編譯器確實試圖警告你,但同樣的事情會發生!
雖然在所有尾隨閉包中包含[weak self]
捕獲在技術上不正確,但它確實減損了代碼的可讀性,並且感覺不像'類似Swift'。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.