为什么将正在进行释放的对象设置为弱属性会导致崩溃

Nik*_*sov 21 weak-references objective-c clang dealloc automatic-ref-counting

Clang的Objective-C自动参考计数中,我们看到以下内容

对于__weak对象,左值更新为指向新的指针,除非新指针是当前正在进行解除分配的对象,在这种情况下,左值更新为空指针.这必须相对于对象的其他赋值,从对象读取以及新指针的最终版本以原子方式执行.

objc-weak.mm中,我们看到以下代码块weak_register_no_lock():

    if (deallocating) {
    if (crashIfDeallocating) {
        _objc_fatal("Cannot form weak reference to instance (%p) of "
                    "class %s. It is possible that this object was "
                    "over-released, or is in the process of deallocation.",
                    (void*)referent, object_getClassName((id)referent));
    } else {
        return nil;
    }
}
Run Code Online (Sandbox Code Playgroud)

我在我的UIViewController子类dealloc方法中设置了一个断点,并尝试[self allowsWeakReference]在lldb中调用,从而产生了NO值.

如果我们尝试将self设置为另一个对象的weak属性,则应用程序将根据objc-weak.mm代码崩溃.

问题是 - 为什么会发生这种情况?铿锵的规格是错的吗?这是objc实现中的一个错误吗?


这是一段简单的代码,可以重现崩溃:

//cc -fmodules -fobjc-arc -g crash.m -o crash
@import Foundation;

@interface Foo : NSObject
@end

@implementation Foo
- (void)dealloc {
  Foo * __weak weakSelf = self; // crashes on this line
}
@end

int main() {
  (void)[[Foo alloc] init];
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*man 1

这不是一个错误:这显然是故意的。这是与规范的偏差,但这是故意的。

根据警告,听起来他们希望更容易地诊断过度释放的情况,而捕获当时正在释放的对象可能只是该主要目标的副作用。

他们还可能认为,如果您在释放时尝试弱化self,并且没有检查weakref(很常见 - 许多块代码通过随时nil可能发生的weakref重复调用!),那么您nil正在为难以调试的错误做好准备。

话虽如此,我很乐意看到运行时更改背后的注释。