【问题标题】:Weak property not zeroing using ARC使用 ARC 不归零的弱属性
【发布时间】:2012-02-24 03:27:29
【问题描述】:

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

// 接口

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

【问题讨论】:

  • 您使用的是什么版本的 iOS/Mac OS?归零弱引用运行时仅适用于 iOS 5/OS 10.7
  • 我在 5.0 模拟器上运行它,目标的部署目标是 5.0,所以版本不匹配应该不是问题。此外,我只是使用原始引用(即不是属性)尝试了这个,并且弱引用没有问题地清零 - 所以这个机制确实因为某种原因不适用于我的属性。

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


【解决方案1】:

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

添加: 看起来我必须扩展我的答案才能清楚地说明为什么它会这样工作。 首先,让我们看看您的示例(来自 cmets):

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;”在一开始。

在多线程环境下弱引用可以变成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 之前自动释放。

【讨论】:

  • 这确实有效,但我有点困惑。如果我写以下 NSData* data = [[NSData alloc] init]; __weak NSData* weakRef = 数据;数据=无; NSAssert(weakRef == nil, @"失败归零");断言按预期通过。 ARC自动发布和立即发布时是否有明确规定的规则?或者是始终假设自动释放的标准做法?
  • 非常感谢您的详尽解释 - 非常感谢。不过有一个挥之不去的小问题;)我理解为什么编译器会想要自动保留一个变量,直到一个方法完成,但为什么要使用自动释放?在方法开始时保留并在它即将返回时释放不是更好(和更一致的方式)来处理它吗?
  • @Mattia,我不知道 :) 实际上描述只是恕我直言,这是编译器执行此类操作的示例。我认为只有编译器的源代码才能回答它的实际工作原理。
猜你喜欢
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多