【问题标题】:Swift Closures - Capturing self as weakSwift Closures - 将自己视为弱者
【发布时间】: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 捕获的任何想法?

【问题讨论】:

  • 不应该有保留周期

标签: swift closures weak-references


【解决方案1】:

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

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

  1. 如果类实例或属性是可选的,则使用弱捕获
  2. 如果类实例或属性是非可选的并且永远不能设置为 nil,则使用 unowned
  3. “你必须……使用 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 都不能解决内存泄漏问题。不过还是谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多