gpt4 book ai didi

ios - 为什么在 dealloc 发生在另一个线程上时尝试创建对 self 的弱引用时我会崩溃?

转载 作者:可可西里 更新时间:2023-11-01 06:00:41 24 4
gpt4 key购买 nike

背景

我们的应用程序有一个类试图实现 Receptionist Pattern for KVO observation .整个应用程序中的其他类(例如 View Controller )创建这个 Receptionist 类的实例以充当 KVO 观察者。每个 Receptionist 实例都保留所有者提供的 block 的副本,当 KVO 通知到达时,Receptionist 实例将在适当的操作队列上调用该副本。

接待员的 dealloc 方法调用 KVO removeObserver 方法。 Owner 将 Receptionist 实例保留为强引用字段,因此当 Owner 被释放时,Receptionist 将在释放过程中将自己作为观察者移除。

崩溃

当 Receptionist 实例在一个线程上收到 KVO 通知,而同一实例的 dealloc 正在另一个线程上进行时,我们看到了来自崩溃领域的报告。接待员的 observeValueForKeyPath:ofObject:change:context: 实现在这一行崩溃:

    __weak typeof(self) weakSelf = self;

崩溃报告中的堆栈跟踪显示这是对 objc_initWeak 的调用,后者调用 weak_register_no_lock,后者调用 _objc_fatal。

这个特定的接待员正在观察其键的对象永远不会被释放。 Owner 也没有被解除分配;所有者正在用另一个接待员实例替换此接待员实例。

困惑

我能理解为一个已经被释放的对象创建一个弱引用是没有用的,但我希望 weakSelf 接收到一个 nil 值,而不是导致崩溃。

documentation for objc_initWeak如果所需引用的参数已开始释放,则明确提及将目标设置为 null。这听起来像是理想的行为,但我认为这不是我所看到的。我不希望用对 objc_initWeak 的显式调用来替换该行,因为我怀疑我能否正确管理释放。

在请求对自身的弱引用之前,接待员真的有责任注意到它自己的释放正在进行中吗?我假设在 NSObject 的释放开始和调用该对象的 dealloc 方法之间存在一些时间窗口,因此 dealloc 方法在对象内发出的信号听起来不稳定。

感谢阅读!

PS:在阅读了 Ken Thomases 提出的问题后进行了大量编辑。

最佳答案

这与弱引用的创建无关。您引用的行只能在对 self 有强烈引用的上下文中运行。

想一想:您看到的崩溃可能发生在您的 observeValueForKeyPath:ofObject:change:context: 实现中的那一行,但是,因为在释放和调用之间显然存在竞争对于该方法,释放也可能发生在该方法调用的分派(dispatch)期间(或其他某个点)。你很容易受到不同的崩溃。因此,对方法的实现进行任何更改都不可能解决问题,因为问题甚至可能在您的方法被调用之前就已经显现。

如果您要在该对象上调用方法,则您有责任保持对该对象的强引用。或者,从另一个角度来看,避免在您不确定在调用期间是否存在的对象指针上调用方法(因为您持有强引用或其他一些 API 保证)。

使用 KVO,您需要在发布最后一个强引用之前移除观察者。

关于ios - 为什么在 dealloc 发生在另一个线程上时尝试创建对 self 的弱引用时我会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47561938/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com