捕获的弱引用指向错误的对象

Captured weak reference pointed to wrong object

如果我在闭包中弱引用 self:

{[weak self] in self!.doSomethinmg()}

并且self被释放,但闭包继续存在。闭包中的 self 是否有可能在将来的某个时候变为非零 - 指向由运行时环境确定的某个随机新对象?

这取决于你想要达到什么。

马丁提出的建议是对的。为了保证您没有任何崩溃并继续处理该实例,您可以使用 weak/strong 舞蹈。否则,使用 self?.

例如,对于 weak/strong 舞蹈,您可以执行以下操作:

{ [weak self] in 
    if let strongSelf = self {
        strongSelf.doSomething()
    }
}

否则

{ [weak self] in 
    self?.doSomething()
}

虽然在第一种情况下属于 self 的实例将继续存在直到闭包被丢弃,但在第二种情况下,相反,因为实例将被放入 nil ,它将表现为一种非操作。

指针是一个变量,它的值是一个内存地址。同样是 对于 weak pointer 是正确的, 但 weak pointer 的值是 (由于一些运行时魔法)如果指向的对象是 nil 释放。如果在 之后相同的内存位置,弱指针变量保持 nil.

所以

{ [weak self] in /* ... */ }

创建一个带有弱指针变量的闭包。那个变量 当指向的对象被释放时设置为 nil。 这可能发生在调用闭包之前或执行期间 闭包,所以 even

{ [weak self] in
   if (self != nil) self!.doSomethinmg()
}

不安全,如果对象在测试之间被释放可能会崩溃 和方法调用。

但在任何时候,弱指针要么指向 原始对象实例或者是 nil。它会 永远不要指向其他一些对象实例。 (可能发生在 无主引用。)

因为不 强制展开弱指针。使用可选链接或 在闭包内创建强引用。

如果删除了对一个实例的所有 strong 引用,那么该实例最终将被释放。但这并不一定意味着引用它的引用将被重用。所有 strong 引用显然都消失了,因为它们必须是为了首先释放它。因此,无论这对内存意味着那些引用职责所需的引用与应用程序无关,因为引用不再存在于其中的任何地方。

剩下 unownedweak 引用。 Apple makes it pretty clear 在实例被释放后尝试访问 unowned 引用的值是一个不,不:

If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.

所以这也与应用程序无关,只是因为它是一个不能被打破的硬性规则。

最后但并非最不重要的一点是,weak 引用。 Apple says this about weak references:

Because a weak reference does not keep a strong hold on the instance it refers to, it’s possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated.

...

You can check for the existence of a value in the weak reference, just like any other optional value, and you will never end up with a reference to an invalid instance that no longer exists.

这里的关键是引用设置为 nil。即使 nil 不代表任何内容,它仍然是一个有效值。而且我觉得可以安全地假设运行时环境不会窃取引用并将其用于其他目的,因为它仍然指向有效值。想象一下否则会是什么样子。

因此,weak 引用与这里的应用程序的相关性只是它们可能在某个时候变成 nil;正如@MartinR 在 中所展示的那样,这甚至可能发生在闭包执行过程中。所以最终的解决方案似乎是在使用它之前从 weak 引用创建一个 strong 引用,也就是 "weak/strong dance":

或者:

{ [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()
}
如果 selfnil

只会导致非操作,但不知道这是否能保证 self 不会在执行过程中被释放如果任意长则关闭:

{ [weak self] in 
    self?.doSomething()
    ...
    self?.doSomethingDownTheLine()
}

所以在这种情况下,进行 weak/strong 舞蹈将保证您的闭包将是全有或全无:

{ [weak self] in 
    guard let strongSelf = self else {   return   }
    strongSelf.doSomething()
    ...
    strongSelf.doSomethingDownTheLine()
}