Swift 闭包 [weak self] 和异步任务

Posted

技术标签:

【中文标题】Swift 闭包 [weak self] 和异步任务【英文标题】:Swift closures [weak self] and async tasks 【发布时间】:2015-09-04 09:35:45 【问题描述】:

想象一种情况,当您想要异步从服务器加载一些文本并将结果显示在 ViewController's UITextField

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 

    //... some long running async operation

    if let textResponse = responseFromServer 
        dispatch_async(dispatch_get_main_queue(),  [weak self] () in
            self?.textField.text = textResponse
        )
    
)

A.) 我需要在用于异步调用的闭包中使用 [weak self] 吗?

我认为我需要这样做,但在阅读了 *** 上的一些 Q/A 并浏览了很多不使用 [weak self] 进行异步任务 + 闭包的开源应用程序之后,我不确定。

即:

你真正想要使用 [unowned self] 或 [weak self] 是您创建强参考循环的时候。 (Shall we always use [unowned self] inside closure in Swift)

在我的例子中没有强引用循环。

或:

但要明确一点,最好还是使用强引用 这种情况。 (Swift ARC and blocks)

B.) 假设使用强参考很好。 当用户在异步加载过程中导航到不同的页面时,ViewController 会发生什么?它会在异步任务完成之前将不可见的 ViewController 保留在应用内存中吗?

【问题讨论】:

【参考方案1】:

这里没有强引用循环(retain cycle)。如果您使用对self 的强引用,则它会在调度块运行后立即解决。如果需要的话,理论上你可以在这里使用强引用。

话虽如此,我建议在这种情况下使用弱引用。在耗时过程的持续时间内保持强引用是没有意义的,仅仅是为了更新已经被关闭的视图的文本字段。如果您正在更新其他模型对象等,也许您可​​能需要保留强引用,但在这种情况下您不需要这样做。作为一般原则,应该尽快释放内存。

更好的是,我还会查看“长时间运行的异步操作”并决定我是否真的希望它在视图控制器被关闭后继续运行。如果不是,我也倾向于取消请求,然后让deinit 取消请求。而且,在这种情况下,您肯定希望使用弱引用(否则在长时间运行的异步操作完成之前不会调用 deinit)。

【讨论】:

以上是关于Swift 闭包 [weak self] 和异步任务的主要内容,如果未能解决你的问题,请参考以下文章

转义闭包捕获 Swift 中的变异“self”参数错误

在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) 'self'

swift中具有多个闭包/ API请求的函数中的异步完成处理

为啥 Swift 闭包不捕获自我?

Swift 中的Closures(闭包)详解

swift - 闭包 -定义和使用