我在启用 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/