Swift Closures - 将自己视为弱者

Posted

技术标签:

【中文标题】Swift Closures - 将自己视为弱者【英文标题】:Swift Closures - Capturing self as weak 【发布时间】:2014-09-22 13:15:09 【问题描述】:

我正在尝试在 Swift 中解决基于闭包的强引用循环。 在下面的代码中,对象由拥有的视图控制器保留。 ProgressHUD 是一个 UIView,它也被拥有的视图控制器保留。每次调用完成处理程序时都会泄露ProgressHUD。使用新的闭包捕获功能时,将 self 声明为 weak 或 unowned 并不能解决内存泄漏问题。

object.setCompletionHandler  [weak self] (error) -> Void in
    if(!error)
        self?.tableView.reloadData()
    
    self?.progressHUD?.hide(false)

但是,如果我在闭包之外为 self 声明一个弱 var,它会修复内存泄漏,如下所示:

weak var weakSelf = self
object.setCompletionHandler  (error) -> Void in
    if(!error)
        weakSelf?.tableView.reloadData()
    
    weakSelf?.progressHUD?.hide(false)

关于为什么这不适用于 Swift 捕获的任何想法?

【问题讨论】:

不应该有保留周期 【参考方案1】:

如果您将闭包分配给类实例的属性,并且闭包通过引用实例或其成员来捕获该实例,您将在闭包和实例之间创建一个强引用循环。 Swift 使用捕获列表来打破这些强引用循环。 source Apple

source sketchyTech 首先,重要的是要明确整个问题只涉及我们分配“类实例属性的闭包”的闭包。每条规则都要记住这一点。 规则:

    如果类实例或属性是可选的,则使用弱捕获 如果类实例或属性是非可选的并且永远不能设置为 nil,则使用 unowned “你必须……使用 in 关键字,即使你省略了参数名称、参数类型和返回类型”

回答您的问题,不应该有保留周期。

【讨论】:

【参考方案2】:

您声明progressHUD由拥有的视图控制器(self)保留,并且您在闭包中引用它......所以将其添加到捕获列表中,然后在闭包中使用捕获的变量,如下所示:

object.setCompletionHandler  [weak self] (error) -> Void in
    if(!error)
        self?.tableView.reloadData()
    
    self?.progressHUD.hide(false)

【讨论】:

无主引用被隐式解包,因此self?.tableView 应更改为self.tableView 你是对的@zxzxlch,我已经编辑了我的解决方案,将unowned self 更改为weak self,并从捕获列表中删除progressHUD。应该没有保留周期。 这与原始问题有何不同?【参考方案3】:

尝试以下方法:

object.setCompletionHandler  [unowned self] (error) -> () in
    if(!error)
        weakSelf?.tableView.reloadData()
    
    weakSelf?.progressHUD?.hide(false)

【讨论】:

如原帖中所述,weak 或 unowned 都不能解决内存泄漏问题。不过还是谢谢。

以上是关于Swift Closures - 将自己视为弱者的主要内容,如果未能解决你的问题,请参考以下文章

Swift之深入解析闭包Closures的使用和捕获变量的原理

Swift 中的Closures(闭包)详解

闭包(Closures)

Swift的闭包,枚举,类和结构体

浅析 JavaScript 中的闭包(Closures)

心态不好,你注定是个弱者!