Reputation: 2258
Just trying to fully understand ARC.
MyView *testView = [[MyView alloc] init];
__weak MyView *weakView = testView;
[weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil];
testView = nil;
if(weakView) {
NSLog(@"WeakView exists!");
}
I don't understand why my NSLog statement is printing. Since weakView is a weak reference to testView, shouldn't it be pointing to nil once testView is set to nil???
Thanks!
Upvotes: 3
Views: 3943
Reputation: 26907
The addObserver
method seems to retain
and autorelease
the view. Thats why the weak reference is not zeroed right after the initial reference is nilled. Just run this code in the debugger:
UIView *testView = [[UIView alloc] init];
__weak UIView *weakView = testView;
@autoreleasepool {
[weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil];
}
testView = nil;
if(weakView) {
NSLog(@"WeakView exists!");
}
Upvotes: 7
Reputation: 21219
Your testView
is local variable and local variables under ARC doesn't have precise lifetime semantics. Read 6.1 at:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization.precise
What does it mean? This means that the compiler can do whatever it wants to do.
Current implementation releases testView
object at the end of the method. But what if the optimizer (now, future, ...) decides that the lifetime is over and it will release it sooner (before the end of the method)?
In other words, you're trying to depend on undefined behavior. Don't do this, don't rely on this. In this case, you never know when the object is really released = weak reference is zeroed.
Upvotes: 0
Reputation: 5316
It may or may not. It goes to nil when the object is deallocated. The fact that you set testView
to nil only implies that you are releasing the object. But the object is not guaranteed to immediately be deallocated.
The problem here is that you are assuming a given value for the retain count. You think that the alloc+init sequence gave you an object with a count of 1 so that when you set testView
to nil it goes to 0 and the object is deallocated.
You should never assume a given retain count. You should always think in terms of relative retain counts. The alloc+init sequence returns a +1 object (not 1 but +1). When you set set testView
to nil ARC calls release
and turns it to a +0 object (not 0, but +0). This means you have no guarantee that it's still accessible. Your weak reference may or may not be valid.
What is in fact happening is that internally in the init method (or the chained init methods of the parents) there has been a call to autorelease
therefore your object does not yet have a refcount of 0. It will get it (and be deallocated) at the next pool drain.
Edit:
Also what Adam says in his reply is correct.
Upvotes: 1