InternationalCodingGuru
InternationalCodingGuru

Reputation: 2258

arc, strong and weak instance variables

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

Answers (3)

Adam
Adam

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

zrzka
zrzka

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

Analog File
Analog File

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

Related Questions