在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
}
}
}
为了避免循环引用,有些引用不希望是强引用。所以在某一时刻,当一个对象的最后一个强引用被移除时,对象本身也被移除。
其他非强引用会发生什么?显然它们不再指向那个对象了,这是有问题的。有两种方法来处理这个问题:
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%,你不使用垃圾时,当对象消失。
如果以上都说不通:
博士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时,使用无主引用。”
这里有一些很好的答案。但是最近对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。你不会失去任何东西,失去时代的力量和无主的自我其实是安全的。但是,您将从消除难以发现和调试的崩溃和错误中获益良多。
我想我应该为视图控制器添加一些具体的例子。很多解释,不仅仅是在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.
}