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 - 将自己视为弱者的主要内容,如果未能解决你的问题,请参考以下文章