本文翻译自:Shall we always use [unowned self] inside closure in Swift
In WWDC 2014 session 403 Intermediate Swift and transcript , there was the following slide 在WWDC 2014会议403 Intermediate Swift和成绩单中 ,有以下幻灯片
The speaker said in that case, if we don't use [unowned self]
there, it will be a memory leak. 发言者说,在这种情况下,如果我们不在那里使用[unowned self]
,那将导致内存泄漏。 Does it mean we should always use [unowned self]
inside closure? 这是否意味着我们应该在闭包内部始终使用[unowned self]
?
On line 64 of ViewController.swift of the Swift Weather app , I don't use [unowned self]
. 在Swift Weather应用程序的ViewController.swift的第64行上 ,我不使用[unowned self]
。 But I update the UI by using some @IBOutlet
s like self.temperature
and self.loadingIndicator
. 但是我通过使用一些@IBOutlet
来更新UI,例如self.temperature
和self.loadingIndicator
。 It may be OK because all @IBOutlet
s I defined are weak
. 可能没问题,因为我定义的所有@IBOutlet
都weak
。 But for safety, should we always use [unowned self]
? 但是为了安全起见,我们应该始终使用[unowned self]
吗?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
#1楼
参考:https://stackoom.com/question/1e2pf/我们是否应该在Swift的闭包内部始终使用-unown-self
#2楼
No, there are definitely times where you would not want to use [unowned self]
. 不,在某些情况下,您肯定不想使用[unowned self]
。 Sometimes you want the closure to capture self in order to make sure that it is still around by the time the closure is called. 有时您希望闭包捕获自身,以确保在调用闭包时它仍然存在。
Example: Making an asynchronous network request 示例:发出异步网络请求
If you are making an asynchronous network request you do want the closure to retain self
for when the request finishes. 如果发出异步网络请求,则确实希望闭包在请求完成时保留self
。 That object may have otherwise been deallocated but you still want to be able to handle the request finishing. 否则该对象可能已被释放,但是您仍然希望能够处理请求完成。
When to use unowned self
or weak self
何时使用unowned self
或weak self
The only time where you really want to use [unowned self]
or [weak self]
is when you would create a strong reference cycle . 真正要使用[unowned self]
或[weak self]
的唯一时间是创建一个强大的参考周期 。 A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around. 一个强大的参考周期是,当所有权循环出现时,对象最终彼此拥有(可能是通过第三方),因此,由于它们都确保彼此粘在一起,因此永远不会将它们释放。
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]
. 阻止该所有权的唯一方法是执行[unowned self]
或[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. 这还包括类是否拥有某个拥有闭包的东西。
Specifically in the example from the video 特别是在视频示例中
In the example on the slide, TempNotifier
owns the closure through the onChange
member variable. 在幻灯片的示例中, TempNotifier
通过onChange
成员变量拥有闭包。 If they did not declare self
as unowned
, the closure would also own self
creating a strong reference cycle. 如果他们没有宣布self
为unowned
,封闭也将自己的self
创造一个有力的参考周期。
Difference between unowned
and weak
unowned
与weak
之间的区别
The difference between unowned
and weak
is that weak
is declared as an Optional while unowned
is not. unowned
和weak
之间的区别在于, weak
被声明为可选, unowned
则不是。 By declaring it weak
you get to handle the case that it might be nil inside the closure at some point. 通过声明它是weak
您可以处理某些情况下它在闭包内部可能为零的情况。 If you try to access an unowned
variable that happens to be nil, it will crash the whole program. 如果您尝试访问一个恰好为nil的unowned
变量,它将使整个程序崩溃。 So only use unowned
when you are positive that variable will always be around while the closure is around 因此,只有当您肯定变量在闭包周围时将始终存在时,才使用unowned
#3楼
If self could be nil in the closure use [weak self] . 如果self在封闭中可能为零,请使用[weak self] 。
If self will never be nil in the closure use [unowned self] . 如果self在封闭中永远不会为零,请使用[unown self] 。
The Apple Swift documentation has a great section with images explaining the difference between using strong , weak , and unowned in closures: Apple Swift文档中有一个很棒的部分,其中的图像说明了在闭包中使用strong , weak和unown之间的区别:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
#4楼
Update 11/2016 更新11/2016
I wrote an article on this extending this answer (looking into SIL to understand what ARC does), check it out here . 我写了一篇有关扩展此答案的文章(研究SIL以了解ARC的作用),请在此处查看 。
Original answer 原始答案
The previous answers don't really give straightforward rules on when to use one over the other and why, so let me add a few things. 前面的答案并没有真正给出何时何时使用另一个为什么的简单明了的规则,所以让我补充一些内容。
The unowned or weak discussion boils down to a question of lifetime of the variable and the closure that references it. 无主或虚弱的讨论可以归结为变量的生存期以及引用它的闭包的问题。
Scenarios 情境
You can have two possible scenarios: 您可以有两种可能的情况:
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 . 在这种情况下,您应该将引用声明为Unown 。 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. 一个常见的例子是在许多小的闭包示例中使用的[unowned self]
,这些闭包在其父的上下文中执行某项操作,并且在其他任何地方都没有被引用而不会超过其父辈。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. 一个常见的示例是[weak delegate]
您可以在某些闭包示例中看到它们引用一个完全不相关的(按生命周期而言)的委托对象。
Actual Usage 实际用法
So, which will/should you actually use most of the times? 那么,您实际上会/应该在大多数时间使用?
Quoting Joe Groff from twitter : 从推特引用乔·格罗夫 :
Unowned is faster and allows for immutability and nonoptionality. 无所有权的速度更快,并允许不变性和非选择性。
If you don't need weak, don't use it. 如果您不需要弱点,请不要使用它。
You'll find more about unowned *
inner workings here . 您可以在此处找到有关无主*
内部工作原理的更多信息。
*
Usually also referred to as unowned(safe) to indicate that runtime checks (that lead to a crash for invalid references) are performed before accessing the unowned reference. *
通常也称为无主(安全),表示在访问无主引用之前执行了运行时检查(导致无效引用崩溃)。
#5楼
Here is brilliant quotes from Apple Developer Forums described delicious details: 以下是来自苹果开发者论坛的精彩语录,描述了美味的细节:
unowned
vs unowned(safe)
vs unowned(unsafe)
unowned
与unowned(safe)
与unowned(unsafe)
unowned(safe)
is a non-owning reference that asserts on access that the object is still alive.unowned(safe)
是一个非所有者引用,在访问时断言该对象仍然有效。 It's sort of like a weak optional reference that's implicitly unwrapped withx!
有点像一个弱的可选引用,它用x!
隐式解开了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(unsafe)
就像ARC中的__unsafe_unretained
一样,它是一个非所有者的引用,但是没有运行时检查该对象在访问时是否仍然有效,因此,悬空的引用将进入垃圾内存。unowned
is always a synonym forunowned(safe)
currently, but the intent is that it will be optimized tounowned(unsafe)
in-Ofast
builds when runtime checks are disabled.unowned
始终是一个同义词unowned(safe)
目前,但目的是,它会进行优化,以unowned(unsafe)
在-Ofast
当运行时检查被禁用的构建。
unowned
vs weak
unowned
与weak
unowned
actually uses a much simpler implementation thanweak
. 实际上,unowned
使用比weak
使用简单得多的实现。 Native Swift objects carry two reference counts, andunowned
references bump the unowned reference count instead of the strong reference count . 本机Swift对象带有两个引用计数,unowned
引用会颠覆无主引用计数,而不是强引用计数 。 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 whenunowned
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. 这将导致扶住当有无主引用稍长的内存,但是这通常不是一个问题,当unowned
时使用,因为相关的对象应该有接近相等的寿命无论如何,这是比简单得多和低开销用于弱引用清零的基于边表的实现。
Update: In modern Swift weak
internally uses the same mechanism as unowned
does . 更新:在现代Swift中, weak
内部使用与unowned
相同的机制 。 So this comparison is incorrect because it compares Objective-C weak
with Swift unonwed
. 所以这个比较是不正确的,因为它比较了Objective-C的weak
和Swift的unonwed
。
Reasons 原因
What is the purpose of keeping the memory alive after owning references reach 0? 在拥有的引用达到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. 对象的最后一个强引用释放后,对象的所有资源都将释放,并且其deinit将运行。 Unowned references only keep the memory alive—aside from the header with the reference counts, its contents is junk. 无主引用仅使内存保持活动状态-除了带有引用计数的标头之外,其内容是垃圾。
Excited, huh? 激动,是吗?
#6楼
According to Apple-doc 根据Apple-doc
Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated. 弱引用始终是可选类型,并且在释放它们引用的实例时自动变为nil。
If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference 如果捕获的引用永远不会为零,则应始终将其捕获为未拥有的引用,而不是弱引用
Example - 范例-
// 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)
}