dealloc中的弱属性设置为nil,但属性的ivar不是nil

时间:2013-04-20 16:02:32

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

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

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

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

@implementation A
@end

实施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为零,但a->_refObject不为零且指向'b'

为什么会发生这种情况?

1 个答案:

答案 0 :(得分: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
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)

     

如果object被注册为__weak对象,并且存储到object中的最后一个值没有>尚未解除分配或开始解除分配,保留该值并将其返回。否则>返回null。

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

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