在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
    }
  }
}

当前回答

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)
        }

    }

}

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

其他回答

不,有些时候你肯定不想使用[u主self]。有时你想让闭包捕获self以确保在闭包被调用时它仍然存在。

示例:发起异步网络请求

如果您正在发出异步网络请求,您确实希望闭包在请求完成时保持自我。该对象可能已经被释放,但您仍然希望能够处理请求的完成。

何时使用无主自我或弱自我

真正需要使用[un主self]或[weak self]的唯一时候是创建强引用循环的时候。强引用循环是指存在一个所有权循环,其中对象最终拥有彼此(可能通过第三方),因此它们永远不会被释放,因为它们都确保彼此存在。

In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self]. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.

特别是在视频中的例子中

在幻灯片上的示例中,TempNotifier通过onChange成员变量拥有闭包。如果它们没有声明self为无主的,闭包也将拥有self,从而创建一个强引用循环。

无主和弱的区别

u主和weak的区别在于weak被声明为Optional,而u主则不是。通过声明它为弱,你可以处理闭包中某个时刻它可能为nil的情况。如果你试图访问一个无主变量,而这个变量恰好是nil,它将使整个程序崩溃。所以只有当你确定这个变量在闭包存在的时候才使用un主

如果以上都说不通:

博士tl;

就像一个隐式打开的可选选项,如果你能保证 引用在它的使用点不会为nil,使用无主。 如果不是,那么你应该使用weak。

解释:

我检索了以下在:弱无主链接。从我收集到的,无主self不能为nil,但弱self可以,并且无主self可以导致悬空指针…这在Objective-C中是臭名昭著的。希望能有所帮助

“无主弱引用和无主引用行为相似,但并不相同。”

Unowned references, like weak references, do not increase the retain count of the object being referred. However, in Swift, an unowned reference has the added benefit of not being an Optional. This makes them easier to manage rather than resorting to using optional binding. This is not unlike Implicitly Unwrapped Optionals . In addition, unowned references are non-zeroing. This means that when the object is deallocated, it does not zero out the pointer. This means that use of unowned references can, in some cases, lead to dangling pointers. For you nerds out there that remember the Objective-C days like I do, unowned references map to unsafe_unretained references.

这就是让人有点困惑的地方。

弱引用和无主引用都不会增加保留计数。

它们都可以用来打破保留循环。那么我们什么时候使用它们呢?

苹果公司的文件显示:

“当一个引用在其生命周期的某个时间点变成nil是有效的时,就使用弱引用。相反,当你知道在初始化过程中设置的引用永远不会为nil时,使用无主引用。”

为了避免循环引用,有些引用不希望是强引用。所以在某一时刻,当一个对象的最后一个强引用被移除时,对象本身也被移除。

其他非强引用会发生什么?显然它们不再指向那个对象了,这是有问题的。有两种方法来处理这个问题:

Weak reference. When the last strong reference to an object goes away, all weak references are set to nil, so a developer can check if the referenced object is there anymore. Quite obviously a weak reference must be an optional, otherwise it couldn’t be set to nil. The strategy to use a weak reference: You write “if let ref = weakref”. Either the reference was still there, and since you just assigned it to a strong reference, it will remain until the end of the “if let”. If you don’t do it this way then you may access the same weak reference twice, and it may be (unexpectedly) not nil on the first access, but nil on the second. You create an unowned reference. If the object goes away, nobody will tell you. It will look as if you have a reference when to the referred object has gone away. You must only use this if you are 100% sure that the referenced object cannot go away early.

使用无主的,如果你已经测量,它是更快的,当你是100%,你不使用垃圾时,当对象消失。

如果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

更新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),表示在访问无主引用之前执行运行时检查(导致无效引用崩溃)。