弱属性未使用ARC归零



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

//接口

@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弱引用不是应该归零吗?如果是这样,我做错了什么?

d尝试一些自定义类,而不是NSData,例如MyData。在其中实现dealloc方法,并在其中设置断点。您会看到,dealloc是在最后一个NSAssert之后被自动释放池调用的。只有在该周之后,引用才会变成nil

添加:看来我必须扩展我的答案来弄清楚,为什么它会这样工作。首先,让我们看看你的例子(来自评论):

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

如预期的那样,weakRefdata = nil之后变成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;"。

在多线程环境中,弱引用可以在if之后变成nil

因此,正确编写的函数应该看起来像:

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

但通常我们不想在任何地方都这样做——这会很难看。因此,我们希望确保争论不会消失在在中间的某个地方。编译器通过自动删除弱引用为我们做这件事。

因此,应该清楚GMWeakRefObj测试用例是如何工作的,为什么不工作——在调用setObjectsetter之前,weakRef是自动释放的。

最新更新