pla*_*a__ 11 weak-references objective-c automatic-ref-counting
我在Objective-C中注意到以下内容,启用了ARC:
让我们有简单的A类和自动合成的弱属性
@interface A
@property (nonatomic, weak) id refObject;
@end
@implementation A
@end
Run Code Online (Sandbox Code Playgroud)
并且实现了dealloc的第二类B.
@interface B
@end
@implementation B
-(void) dealloc
{
NSLog(@"In dealloc");
}
@end
Run Code Online (Sandbox Code Playgroud)
最后,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
Run Code Online (Sandbox Code Playgroud)
如果我在中设置断点[B dealloc]并检查[A refObject]属性,我可以看到它a.refObject是nil但a->_refObject不是nil并且指向'b'
任何想法为什么会发生?
Mar*_*n R 23
简短回答:实例变量a->_refObject尚未(尚未)-[B dealloc],但每次访问该弱指针都是通过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
Run Code Online (Sandbox Code Playgroud)
并object_dispose()从称为-[NSObject dealloc](如可在可见
http://www.opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm).
因此,在调用(编译器生成)之前-[B dealloc],a->_refObject不是nil [super dealloc].
所以问题仍然存在:为什么a.refObject在那时返回零?
原因是,对于每次访问弱指针,ARC编译器都会生成对objc_loadWeak()或的调用objc_loadWeakRetained().从文档:
id objc_loadWeakRetained(id*object)
如果object被注册为__weak对象,并且存储到对象中的最后一个值尚未被释放或已开始取消分配,则保留该值并返回该值.否则>返回null.
因此,即使a->refObject在那时不是nil,通过objc_loadWeakRetained()(通过属性访问器方法完成)访问弱指针也会返回nil,因为B对象的释放已经开始.
调试器a->refObject直接访问而不调用objc_loadWeak().