在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;
}
}
我在UIViewController子类dealloc
方法中设置了一个断点,并尝试在lldb中调用[self allowsWeakReference]
,从而产生了NO
值。
如果我们尝试将 self 设置为另一个对象的弱属性,应用程序将根据 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;
}
这不是一个错误:它显然是非常有意为之的。这是对规格的偏差,但这是有意为之的。
根据警告,听起来他们希望更容易诊断过度释放的情况,而捕获当时正在释放的对象可能只是该主要目标的副作用。
他们可能还会考虑,如果你试图在解除分配的同时削弱self
,并且你没有检查nil
弱引用(很常见 - 许多块代码反复调用弱引用,随时可能nil
!),你正在为难以调试的错误做好准备。
综上所述,我很想看到运行时更改背后的注释。