Swift Closures - Capturing self as weak

我怕爱的太早我们不能终老 提交于 2019-11-29 02:48:31

问题


I am trying to resolve a closure based strong reference cycle in Swift.
In the code below, object is retained by the owning view controller. ProgressHUD is a UIView that's also retained by the owning view controller. ProgressHUD is leaked every time the completion handler is called. When using the new closure capture feature, declaring self as weak or unowned does not resolve the memory leak.

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

However, if I declare a weak var for self outside of the closure, it fixes the memory leak, like this:

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

Any ideas as to why this is not working with Swift capturing?


回答1:


If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. source Apple

source sketchyTech First, it is important to make clear that this whole issue only concerns closures where we are assigning "a closure to a property of a class instance". Keep this in mind with each rule. The rules:

  1. use weak capture if the class instance or property is an optional
  2. use unowned if the class instance or property is non-optional and can never be set to nil
  3. "you must ... use the in keyword, even if you omit the parameter names, parameter types, and return type"

In answear to your question there should be no retain cycle.




回答2:


You stated that progressHUD is retained by the owning view controller (self) and you reference it in your closure...so add it to the capture list and then use the captured variable in the closure as follows:

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



回答3:


This is how I have been doing it:

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

        weakSelf.progressHUD?.hide(false)
    }
}



回答4:


Try the following:

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


来源:https://stackoverflow.com/questions/25975073/swift-closures-capturing-self-as-weak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!