我们应该总是在 Swift 的闭包中使用 [unowned self] [英] Shall we always use [unowned self] inside closure in Swift
问题描述
在 WWDC 2014 session 403 ,我不使用[unowned self]
.但是我通过使用一些 @IBOutlet
来更新 UI,比如 self.temperature
和 self.loadingIndicator
.可能没问题,因为我定义的所有 @IBOutlet
都是 weak
.但是为了安全起见,我们应该总是使用 [unowned self]
吗?
class TempNotifier {var onChange: (Int) ->void = {_ in }var currentTemp = 72在里面() {onChange = { [unowned self] temp inself.currentTemp = 温度}}}
不,在某些时候您肯定不想使用 [unowned self]
.有时您希望闭包捕获 self 以确保在调用闭包时它仍然存在.
示例:发出异步网络请求
如果您正在发出异步网络请求,您确实希望闭包在请求完成时保留self
.该对象可能已被释放,但您仍然希望能够处理请求完成.
何时使用unowned self
或weak self
您真正想要使用 [unowned self]
或 [weak self]
的唯一时间是您创建一个 强参考周期.强引用循环是指当存在一个所有权循环时,对象最终相互拥有(可能通过第三方),因此它们永远不会被释放,因为它们都确保彼此保持存在.
在闭包的特定情况下,您只需要意识到在它内部引用的任何变量都由闭包拥有".只要闭包在附近,这些对象就可以保证在附近.停止这种所有权的唯一方法是执行[unowned self]
或[weak self]
.因此,如果一个类拥有一个闭包,并且该闭包捕获了对该类的强引用,那么在该闭包和该类之间就有了一个强引用循环.这也包括类是否拥有拥有闭包的东西.
特别是视频中的例子
在幻灯片的示例中,TempNotifier
通过 onChange
成员变量拥有闭包.如果他们没有将 self
声明为 unowned
,闭包也会拥有 self
,从而创建一个强引用循环.
unowned
和 weak
的区别
unowned
和 weak
的区别在于 weak
被声明为 Optional 而 unowned
不是.通过将它声明为 weak
,您可以处理在某些时候它在闭包内可能为零的情况.如果您尝试访问一个恰好为零的 unowned
变量,它将导致整个程序崩溃.因此,仅当您确定变量将始终存在而闭包存在时才使用 unowned
In WWDC 2014 session 403 Intermediate Swift and transcript, there was the following slide
The speaker said in that case, if we don't use [unowned self]
there, it will be a memory leak. Does it mean we should always use [unowned self]
inside closure?
On line 64 of ViewController.swift of the Swift Weather app, I don't use [unowned self]
. But I update the UI by using some @IBOutlet
s like self.temperature
and self.loadingIndicator
. It may be OK because all @IBOutlet
s I defined are weak
. But for safety, should we always use [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
No, there are definitely times where you would not want to use [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. 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
The only time where you really want to use [unowned self]
or [weak self]
is when you would create a strong reference cycle. 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]
. 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. If they did not declare self
as unowned
, the closure would also own self
creating a strong reference cycle.
Difference between unowned
and weak
The difference between unowned
and weak
is that weak
is declared as an Optional while unowned
is not. By declaring it weak
you get to handle the case that it might be nil inside the closure at some point. If you try to access an unowned
variable that happens to be nil, it will crash the whole program. So only use unowned
when you are positive that variable will always be around while the closure is around
这篇关于我们应该总是在 Swift 的闭包中使用 [unowned self]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!