ios – 在swift中将捕获列表正确放置在嵌套闭包中

前端之家收集整理的这篇文章主要介绍了ios – 在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.
        */
    }
}@H_404_5@ 
 

在这个例子中,[weak self]用于两个尾随闭包,但是如果我从尾随闭包中的任何一个省略[weak self],编译器是非常高兴的.

所以我留下了3个选项来定义我的捕获列表:

>在每个嵌套的闭包上定义捕获,导致引用
>仅在第一个闭包上定义捕获.
>仅对实际使用引用的最嵌套的闭包定义捕获.

我的问题是:

If I know that my ExampleDataSource could be nil at some point,what is the best option to go with?

解决方法@H_502_26@
请注意,GCD dispatch_async不会导致保留周期.换句话说,当块完成执行时,GCD将不会保留块内的任何引用.

类之间的强引用也不同,也不适用于分配给实例的属性的闭包中的强引用. Apple Documentation

也就是说,在这个例子中,正确的答案是选项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")
        }
    }
}@H_404_5@ 
 

首先我创建,var myDataSource:ExampleDataSource? = ExampleDataSource().

然后我运行myDataSource.loadContent().

在完成处理程序有机会运行之前,我设置myDataSource = nil,删除对它的所有引用.

调试控制台表示对自身的引用未被保留:

init()
loadContent()
deinit
loadedContent@H_404_5@ 
 

看起来我们找到了我们的答案!但是为了完成这个目的,让我们来考察替代方案…

如果[weak self]被捕获在只​​有内部最后面的闭包,GCD将保留ExampleDataSource,直到块完成执行,这就解释了为什么调试看起来像这样:

init()
loadContent()
loadedContent
deinit@H_404_5@ 
 

同样的事情会发生,如果没有捕获列表被包括,我们从来没有可选地解开自己,尽管编译器,确实试图警告你!

虽然在所有尾随关闭中包含[弱自我]捕获技术上并不是技术上不正确的,但它确实会降低代码的可读性,并且不会感觉到“像Swift一样”.

猜你在找的iOS相关文章