问题 迅速关闭 - 捕捉自我弱势


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

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

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

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

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


8238
2017-09-22 13:15


起源

不应该有保留周期 - newacct


答案:


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

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

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

在你的问题的答案中,应该没有保留周期。


13
2017-12-18 08:39





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

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

4
2017-12-10 04:40



无主引用是隐式解包的 self?.tableView 应该改为 self.tableView。 - Benjamin Cheah
你是对的@zxzxlch,我已经通过将无主的自我改为弱自我来编辑我的解决方案,并从捕获列表中删除progressHUD。应该没有保留周期。 - dferrero
这与原始问题有何不同? - Ashley Mills


这就是我一直在做的事情:

object.setCompletionHandler { [weak self] (error) -> Void in
    if let weakSelf = self {
        if (!error) {
            weakSelf.tableView.reloadData()
        }

        weakSelf.progressHUD?.hide(false)
    }
}

-2
2017-12-21 20:36



这完全倒退了。将'weakSelf'重命名为'strongSelf'。 'let'为您提供了强有力的参考。 - Graham Perks


请尝试以下方法:

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

-4
2017-10-14 02:15



正如原帖中所述,无论是弱者还是无人物都无法解决内存泄漏问题。谢谢。 - Fergal Rooney