弱属性不使用 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
Aren ARC弱引用不应该归零吗?如果是这样,我做错了什么?
I have the following simple code for an object that holds a weak reference:
// interface
@interface GMWeakRefObj : NSObject
@property (weak) id object;
@end
// implementation
@implementation GMWeakRefObj
@synthesize object;
@end
When I run the following test code it fails on the second assert:
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
Aren't ARC weak references supposed to be zeroing? And if so what am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试使用一些自定义类来代替
d
的NSData
,例如MyData
。在其中实现dealloc方法并在其中设置断点。您将看到,dealloc
由自动释放池在最后一个NSAssert
之后调用。只有在那一周之后,引用才会变为nil
。添加:
看来我必须扩展我的答案才能弄清楚为什么它会这样工作。
首先,让我们看一下您的示例(来自注释):
它按预期工作,
weakRef
在data = nil
之后变为nil
。下一个示例也可以工作:但上一个示例不起作用:
唯一的区别是我们使用弱引用来输出日志。为什么?
(答案的其余部分可能是错误的:))
想象您
NSLog
(或我们在data = nil
之前调用的任何其他函数/选择器) )依赖于它的参数不为nil
。例如,它有“if (arg == nil) return;”一开始。在多线程环境中,弱引用可以在
if
之后变成nil
。所以正确编写的函数应该是这样的:
但通常我们不想在任何地方都这样做——它会很难看。所以我们要确保争论不会在中间的某个地方消失。编译器通过自动释放弱引用来为我们做到这一点。
因此,应该清楚您的
GMWeakRefObj
测试用例为何不起作用 -weakRef
在调用setObject
setter 之前自动释放。Try some custom class class instead of
NSData
ford
, e.g.MyData
. Implementdealloc
method in it and set breakpoint in it. You will see, thatdealloc
is called by autorelease pool after the lastNSAssert
. Only after that week reference will becomenil
.ADD:
Looks like I have to extend my answer to make it clear, why it works that way.
First, lets look at your example (from comments):
It works as expected,
weakRef
becomenil
afterdata = nil
. The next example works too:But the last example doesn't work:
The only difference is that we use weak reference to output log. Why?
(the rest of the answer can be wrong :) )
Imaging that you
NSLog
(or any other function/selector we call beforedata = nil
) rely on it's argument not to benil
. For example, it has "if (arg == nil) return;" at the very beginning.In multithreaded environment weak reference can become
nil
afterif
.So properly written function should look like:
But usually we don't want to do it everywhere -- it will be ugly. So we want to be sure that arguments will not disappear somewhere in the middle. Compiler does it for us by autoreleasing weak reference.
So, it should be clear how, why your
GMWeakRefObj
test case doesn't work --weakRef
is autoreleased before callingsetObject
setter.