在2014年WWDC会议403中,有以下幻灯片

演讲者说,在那种情况下,如果我们不在那里使用[u主self],就会发生内存泄漏。这是否意味着我们应该总是在闭包中使用[ucontrolled self] ?

在Swift Weather应用程序的ViewController.swift的第64行,我没有使用[u主self]。但是我通过使用一些@ iboutlet来更新UI,比如self。温度和自加载指示器。这可能没问题,因为我定义的所有@IBOutlets都是弱的。但是为了安全起见,我们应该总是使用[无主的自我]吗?

class TempNotifier {
  var onChange: (Int) -> Void = {_ in }
  var currentTemp = 72
  init() {
    onChange = { [unowned self] temp in
      self.currentTemp = temp
    }
  }
}

当前回答

如果self可以在闭包中为nil,请使用[weak self]。

如果self在闭包中永远不会为nil,请使用[无主的self]。

Apple Swift文档中有一个很好的章节,用图片解释了在闭包中使用strong、weak和u主的区别:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

其他回答

根据Apple-doc

弱引用总是可选类型,并且是自动的 当它们引用的实例被释放时变为nil。 如果捕获的引用永远不会变成nil,那么它应该始终被捕获为无主引用,而不是弱引用

的例子,

    // if my response can nil use  [weak self]
      resource.request().onComplete { [weak self] response in
      guard let strongSelf = self else {
        return
      }
      let model = strongSelf.updateModel(response)
      strongSelf.updateUI(model)
     }

    // Only use [unowned self] unowned if guarantees that response never nil  
      resource.request().onComplete { [unowned self] response in
      let model = self.updateModel(response)
      self.updateUI(model)
     }

更新11/2016

我写了一篇关于扩展这个答案的文章(通过研究SIL来理解ARC做了什么),请在这里查看。

原来的答案

前面的答案并没有给出什么时候使用一种而不是另一种的直接规则,所以让我补充一些东西。

无主或弱的讨论归结为变量和引用它的闭包的生命周期问题。

场景

你可以有两个可能的场景:

The closure have the same lifetime of the variable, so the closure will be reachable only until the variable is reachable. The variable and the closure have the same lifetime. In this case you should declare the reference as unowned. A common example is the [unowned self] used in many example of small closures that do something in the context of their parent and that not being referenced anywhere else do not outlive their parents. The closure lifetime is independent from the one of the variable, the closure could still be referenced when the variable is not reachable anymore. In this case you should declare the reference as weak and verify it's not nil before using it (don't force unwrap). A common example of this is the [weak delegate] you can see in some examples of closure referencing a completely unrelated (lifetime-wise) delegate object.

实际使用

那么,大多数时候你会/应该使用哪种呢?

引用乔·格罗夫在推特上的话:

无主更快,并且允许不可变性和非可选性。 如果你不需要弱,就不要用它。

你会在这里找到更多关于无主内部工作的信息。

*通常也称为无主(safe),表示在访问无主引用之前执行运行时检查(导致无效引用崩溃)。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let controller = storyboard.instantiateViewController(withIdentifier: "AnotherViewController")
        self.navigationController?.pushViewController(controller, animated: true)

    }

}



import UIKit
class AnotherViewController: UIViewController {

    var name : String!

    deinit {
        print("Deint AnotherViewController")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        print(CFGetRetainCount(self))

        /*
            When you test please comment out or vice versa

         */

//        // Should not use unowned here. Because unowned is used where not deallocated. or gurranted object alive. If you immediate click back button app will crash here. Though there will no retain cycles
//        clouser(string: "") { [unowned self] (boolValue)  in
//            self.name = "some"
//        }
//


//
//        // There will be a retain cycle. because viewcontroller has a strong refference to this clouser and as well as clouser (self.name) has a strong refferennce to the viewcontroller. Deint AnotherViewController will not print
//        clouser(string: "") { (boolValue)  in
//            self.name = "some"
//        }
//
//


//        // no retain cycle here. because viewcontroller has a strong refference to this clouser. But clouser (self.name) has a weak refferennce to the viewcontroller. Deint AnotherViewController will  print. As we forcefully made viewcontroller weak so its now optional type. migh be nil. and we added a ? (self?)
//
//        clouser(string: "") { [weak self] (boolValue)  in
//            self?.name = "some"
//        }


        // no retain cycle here. because viewcontroller has a strong refference to this clouser. But clouser nos refference to the viewcontroller. Deint AnotherViewController will  print. As we forcefully made viewcontroller weak so its now optional type. migh be nil. and we added a ? (self?)

        clouser(string: "") {  (boolValue)  in
            print("some")
            print(CFGetRetainCount(self))

        }

    }


    func clouser(string: String, completion: @escaping (Bool) -> ()) {
        // some heavy task
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
            completion(true)
        }

    }

}

如果你不确定[无主自我],那么使用[弱自我]

我想我应该为视图控制器添加一些具体的例子。很多解释,不仅仅是在Stack Overflow上,真的很好,但我用现实世界的例子工作得更好(@drewag在这方面有一个很好的开始):

If you have a closure to handle a response from a network requests use weak, because they are long lived. The view controller could close before the request completes so self no longer points to a valid object when the closure is called. If you have closure that handles an event on a button. This can be unowned because as soon as the view controller goes away, the button and any other items it may be referencing from self goes away at the same time. The closure block will also go away at the same time. class MyViewController: UIViewController { @IBOutlet weak var myButton: UIButton! let networkManager = NetworkManager() let buttonPressClosure: () -> Void // closure must be held in this class. override func viewDidLoad() { // use unowned here buttonPressClosure = { [unowned self] in self.changeDisplayViewMode() // won't happen after vc closes. } // use weak here networkManager.fetch(query: query) { [weak self] (results, error) in self?.updateUI() // could be called any time after vc closes } } @IBAction func buttonPress(self: Any) { buttonPressClosure() } // rest of class below. }

这里有一些很好的答案。但是最近对Swift实现弱引用方式的改变应该会改变每个人对弱self和无主self的使用决策。以前,如果你需要最好的性能,使用无主的自我优于弱自我,只要你能确定自我永远不会为nil,因为访问无主的自我比访问弱自我快得多。

但是Mike Ash已经记录了Swift如何更新弱变量的实现以使用侧边表,以及这如何极大地提高弱自我性能。

https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html

Now that there isn't a significant performance penalty to weak self, I believe we should default to using it going forward. The benefit of weak self is that it's an optional, which makes it far easier to write more correct code, it's basically the reason Swift is such a great language. You may think you know which situations are safe for the use of unowned self, but my experience reviewing lots of other developers code is, most don't. I've fixed lots of crashes where unowned self was deallocated, usually in situations where a background thread completes after a controller is deallocated.

bug和崩溃是编程中最耗时、最痛苦、最昂贵的部分。尽最大努力编写正确的代码并避免它们。我建议制定一条规则,永远不要强制打开可选项,永远不要使用无主self而不是弱self。你不会失去任何东西,失去时代的力量和无主的自我其实是安全的。但是,您将从消除难以发现和调试的崩溃和错误中获益良多。