如果我在封闭中弱引用自我:
{[weak self] in self!.doSomethinmg()}
self
被解除分配,但封闭仍然存在。闭包中的self
是否可能在将来的某个时刻变为非零 - 指向由运行时环境确定的一些随机新对象?
答案 0 :(得分:5)
指针是一个变量,其值是内存地址。同样如此
如果弱指针,则为true,但弱指针的值为
(由于某些运行时魔法)如果指向的对象是,则设置为nil
释放。如果在此处创建了任何新对象,则无关
稍后相同的内存位置,弱指针变量保持nil
。
所以
{ [weak self] in /* ... */ }
使用弱指针变量创建一个闭包。那个变量
取消分配指向对象时设置为nil
。
这可能发生在调用闭包之前或执行期间
关闭,所以甚至
{ [weak self] in
if (self != nil) self!.doSomethinmg()
}
是不安全的,如果在测试之间取消分配对象,则可能会崩溃 和方法调用。
但无论如何,弱指针指向
原始对象实例或是nil
。它会
从不指向其他一些对象实例。 (可能发生
无主的引用。)
由于Lorenzo says,没有 强行打开弱指针。使用可选链接或 在闭包内创建一个强引用。
答案 1 :(得分:1)
这取决于你想要达到的目标。
马丁建议做对了。为了保证您不会遇到任何崩溃并继续处理该实例,您可以使用weak
/ strong
跳舞。否则,请使用self?
。
例如,使用weak
/ strong
舞蹈,您可以执行以下操作:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
否则
{ [weak self] in
self?.doSomething()
}
虽然在第一种情况下属于self
的实例将继续存在,直到关闭将被丢弃,在第二种情况下,相反,因为实例将被放到nil
,它将表现为一种非操作。
答案 2 :(得分:0)
如果删除了对实例的所有strong
引用,则最终将释放该实例。但这并不一定意味着引用它的引用将被重用。所有strong
引用显然已经消失了,因为它们必须首先被释放。因此,对于内存而言,这些引用所需的引用与应用程序无关,因为引用不再存在于其中的任何位置。
还剩下unowned
和weak
个引用。尝试在实例释放后访问unowned
引用的值的Apple makes it pretty clear是否,否:
如果在取消分配该实例后尝试访问无主引用的值,则会出现运行时错误。
因此,这也与应用程序无关,只是因为它不是一个难以打破的规则。
最后但并非最不重要的是weak
引用。 Apple says this about weak references:
因为弱引用不能保持对实例的强烈保持 它指的是,该实例可能在被释放时被释放 弱参考仍然指的是它。因此,ARC 当实例表示它时,自动设置一个弱引用为nil 是指被解除分配。
...
您可以检查弱引用中是否存在值 像任何其他可选值一样,你永远不会得到一个 引用不再存在的无效实例。
这里的关键是参考设置为nil
。即使nil
代表什么都没有,它仍然是一个有效的值。我觉得可以安全地假设运行时环境不会窃取引用并在它仍然指向有效值时将其用于其他目的。想象一下它会是什么样的。
因此,此处针对weak
引用的应用程序的相关性仅仅是它们可能在某些时候变为nil
;正如@MartinR在his answer中所示,这甚至可能发生在关闭的执行中期。所以最终解决方案似乎是在使用它之前从strong
引用创建weak
引用,也就是“弱/强舞”:
或者:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
或
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
如果闭包由一个可选链组成:
{ [weak self] in
self?.doSomething()
}
如果self
为nil
,只会导致非操作,但不知道是否有任何保证self
在关闭执行期间不会被解除分配这是任意长的:
{ [weak self] in
self?.doSomething()
...
self?.doSomethingDownTheLine()
}
所以在这种情况下,做弱/强舞会保证你的关闭是全有或全无的:
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
...
strongSelf.doSomethingDownTheLine()
}