在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
}
}
}
这里有一些很好的答案。但是最近对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。你不会失去任何东西,失去时代的力量和无主的自我其实是安全的。但是,您将从消除难以发现和调试的崩溃和错误中获益良多。
为了避免循环引用,有些引用不希望是强引用。所以在某一时刻,当一个对象的最后一个强引用被移除时,对象本身也被移除。
其他非强引用会发生什么?显然它们不再指向那个对象了,这是有问题的。有两种方法来处理这个问题:
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%,你不使用垃圾时,当对象消失。
不,有些时候你肯定不想使用[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主
这里有一些很好的答案。但是最近对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。你不会失去任何东西,失去时代的力量和无主的自我其实是安全的。但是,您将从消除难以发现和调试的崩溃和错误中获益良多。
以下是来自苹果开发者论坛的精彩语录:
无主vs无主(安全)vs无主(不安全)
unowned(safe) is a non-owning reference that asserts on access that
the object is still alive. It's sort of like a weak optional reference
that's implicitly unwrapped with x! every time it's accessed.
unowned(unsafe) is like __unsafe_unretained in ARC—it's a non-owning
reference, but there's no runtime check that the object is still alive
on access, so dangling references will reach into garbage memory.
unowned is always a synonym for unowned(safe) currently, but the
intent is that it will be optimized to unowned(unsafe) in -Ofast
builds when runtime checks are disabled.
无主vs弱
unowned actually uses a much simpler implementation than weak.
Native Swift objects carry two reference counts, and unowned
references bump the unowned reference count instead of the strong
reference count. The object is deinitialized when its strong reference
count reaches zero, but it isn't actually deallocated until the
unowned reference count also hits zero. This causes the memory to be
held onto slightly longer when there are unowned references, but that
isn't usually a problem when unowned is used because the related
objects should have near-equal lifetimes anyway, and it's much simpler
and lower-overhead than the side-table based implementation used for
zeroing weak references.
更新:在现代Swift中,weak内部使用与un物主相同的机制。所以这个比较是不正确的,因为它比较了Objective-C的弱和Swift的unonwed。
原因
What is the purpose of keeping the memory alive after owning references reach 0? What happens if code attempts to do something with
the object using an unowned reference after it is deinitialized?
The
memory is kept alive so that its retain counts are still available.
This way, when someone attempts to retain a strong reference to the
unowned object, the runtime can check that the strong reference count
is greater than zero in order to ensure that it is safe to retain the
object.
What happens to owning or unowned references held by the object? Is their lifetime decoupled from the object when it is deinitialized or
is their memory also retained until the object is deallocated after
the last unowned reference is released?
All resources owned by the object are released as soon as the object's
last strong reference is released, and its deinit is run. Unowned
references only keep the memory alive—aside from the header with the
reference counts, its contents is junk.
兴奋,是吗?