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?
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.