为什么将正在被释放的对象设置为weak属性会导致崩溃?

23

Clang的Objective-C自动引用计数中,我们看到以下内容:

对于__weak对象,lvalue将被更新为指向新的pointee,除非新的pointee是当前正在进行解分配的对象,在这种情况下,lvalue将被更新为null指针。这必须与对该对象的其他赋值、对该对象的读取以及新pointee的最终释放同时执行。

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代码崩溃。
问题是 - 为什么会发生这种情况?clang的规范是错误的吗?这是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;
}

那么你想知道什么?为什么你的应用程序崩溃了,还是为什么将弱指针设置为正在释放的对象会导致空值?另外,你为什么认为这两件事情有关系呢? - trojanfoe
我稍微编辑了我的问题,使用了最新的objc-weak.mm源代码。 - Nikita Ilyasov
那似乎是关键,决定它是否按照文档执行或像你所说的崩溃。因此,我会假设大部分/全部时间都会被传递为“false”。你需要在源代码中进行进一步跟踪以实际查看影响。 - trojanfoe
可能需要用于 Swift ... - Amin Negm-Awad
我之前关于这个从版本680开始的说法似乎有误。在早期版本中,只有一个版本,但是从查看weak_register_no_lock源代码来看,当进行解除分配时它总是会崩溃。 - user102008
显示剩余10条评论
1个回答

1

这不是一个bug:显然是故意的。这是与规范的偏离,但这是故意的。

根据警告,听起来他们想要使诊断过度释放的情况更容易,并且捕获正在被释放的对象可能只是那个主要目标的副作用。

他们还可能考虑到,如果您尝试在被释放时弱化 self,并且没有检查 nil 弱引用(非常常见 - 许多块代码通过弱引用重复调用,可能随时会变成 nil!) ,你正在为难以调试的错误设置自己。

尽管如此,我很想看到那个运行时更改背后的注释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接