使用ARC的弱属性不归零

时间:2012-02-01 12:43:13

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

对于包含弱引用的对象,我有以下简单代码:

// interface

@interface GMWeakRefObj : NSObject
@property (weak) id object;
@end

//实施

@implementation GMWeakRefObj 
@synthesize object;
@end

当我运行以下测试代码时,它在第二个断言上失败:

NSData* d = [[NSData alloc] init];
GMWeakRefObj* weakRef = [[GMWeakRefObj alloc] init];
weakRef.object = d;
NSAssert(weakRef.object != nil, @"Reference wasn't assigned");
d = nil;
NSAssert(weakRef.object == nil, @"Reference wasn't zeroed"); // <-- FAIL

ARC弱引用是不是应该归零?如果是这样,我做错了什么?

1 个答案:

答案 0 :(得分:3)

NSData尝试一些自定义班级而不是d,例如MyData。在其中实现dealloc方法并在其中设置断点。您将看到,在最后dealloc之后,自动释放池会调用NSAssert。只有在那一周之后,参考才会成为nil

ADD: 看起来我必须扩展我的答案,以明确,为什么它的工作方式。 首先,让我们看看你的例子(来自评论):

NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");

按预期工作,weakRefnil后变为data = nil。下一个例子也有效:

NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
NSLog(@"%@", data);
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");

但最后一个例子不起作用:

NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
NSLog(@"%@", weakRef);
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");

唯一的区别是我们使用弱引用输出日志。为什么呢?

(其余答案可能是错误的:))

NSLog(或我们在data = nil之前调用的任何其他函数/选择器)的成像依赖于它的参数不是nil。例如,它有“if(arg == nil)return;”在一开始。

在多线程环境中,弱引用可以 <{em> nil成为if

所以正确编写的函数应如下所示:

  // ...
  T* local_arg = arg;   // NOTE: it is strong!
  if (local_arg == nil)
    return;
  // work with local_arg here, not with arg
  // ...

但通常我们不想在任何地方都这样做 - 这将是丑陋的。因此,我们希望确保参数不会在中间某处消失。编译器通过自动释放弱引用为我们做。

因此,应该清楚为什么GMWeakRefObj测试用例不起作用 - weakRef在调用setObject setter之前自动释放。