objective-c - 弱属性在 dealloc 中设置为 nil 但属性的 ivar 不是 nil

标签 objective-c automatic-ref-counting weak-references

我在启用 ARC 的 Objective-C 中注意到以下内容:

让我们拥有简单的 A 类和自动合成的弱属性

@interface A
@property (nonatomic, weak) id refObject;
@end

@implementation A
@end

第二类 B 实现了 dealloc

@interface B
@end

@implementation B
-(void) dealloc
{
    NSLog(@"In dealloc");
}
@end

最后在 A 类的某个地方有以下内容:

@implementation A
...
-(void) foo
{
   B* b = [B new];
   self.refObject = b;
   // Just use b after the weak assignment
   // in order to not dealloc 'b' before assignement 
   NSLog(@"%@", b);
}
...
@end 

如果我在 [B dealloc] 中设置断点并检查 [A refObject] 属性,我可以看到 a.refObject 为 nil但是 a->_refObject 不是 nil 并且指向 'b'

知道为什么会这样吗?

最佳答案

简答:实例变量a->_refObject-[B dealloc]中(还)不是nil, 但是每次对该弱指针的访问都是通过 ARC 运行时函数完成的 如果释放已经开始,则返回 nil。

长答案:通过设置观察点,您可以看到 a->_refObject 在结束时设置为 nil 释放过程。堆栈回溯(命中观察点时)如下所示:

frame #0: 0x00007fff8ab9f0f8 libobjc.A.dylib`arr_clear_deallocating + 83
frame #1: 0x00007fff8ab889ee libobjc.A.dylib`objc_clear_deallocating + 151
frame #2: 0x00007fff8ab88940 libobjc.A.dylib`objc_destructInstance + 121
frame #3: 0x00007fff8ab88fa0 libobjc.A.dylib`object_dispose + 22
frame #4: 0x0000000100000b27 weakdealloc`-[B dealloc](self=0x000000010010a640, _cmd=0x00007fff887f807b) + 151 at main.m:28
frame #5: 0x0000000100000bbc weakdealloc`-[A foo](self=0x0000000100108290, _cmd=0x0000000100000e6f) + 140 at main.m:41
frame #6: 0x0000000100000cf5 weakdealloc`main(argc=1, argv=0x00007fff5fbff968) + 117 at main.m:52
frame #7: 0x00007fff8c0987e1 libdyld.dylib`start + 1

object_dispose() 是从-[NSObject dealloc] 调用的(可以在 http://www.opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm ).

因此在 -[B dealloc] 中,a->_refObject 在(编译器生成的)[super dealloc] 之前不是 nil打电话。

所以问题仍然存在:为什么 a.refObject 在那个时候返回 nil?

原因是每次访问弱指针时,ARC 编译器都会生成 调用 objc_loadWeak()objc_loadWeakRetained()。来自documentation :

id objc_loadWeakRetained(id *object)

If object is registered as a __weak object, and the last value stored into object has not > yet been deallocated or begun deallocation, retains that value and returns it. Otherwise > returns null.

所以即使此时 a->refObject 不为 nil,访问弱指针 通过 objc_loadWeakRetained()(由属性访问器方法完成)返回 nil, 因为 B 对象的释放已经开始。

调试器直接访问a->refObject,不调用objc_loadWeak()

关于objective-c - 弱属性在 dealloc 中设置为 nil 但属性的 ivar 不是 nil,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16122347/

相关文章:

javascript - stringByEvaluatingJavaScriptFromString 问题

javascript - 如何使用 Javascript 与 Objective-c 代码进行通信?

ios - 有关推送到新 DetailView 的信息

ios - 即使已发布 CIImageRefs,CIContext 内存泄漏

objective-c - ARC是否可以降低我的峰值内存占用量?

objective-c - ARC 问题 : No known instance method for selector 'appendPartWithFileData:mimeType:name:'

c# - C# 中 coSTLy 对象的内存管理/缓存

objective-c - 如何为项目中的单个文件禁用 ARC?

c# - 线程和垃圾收集

python - 使用嵌套的 weakref 创建类实例的深拷贝