cs44
cs44

Reputation: 1290

Blocks with reference to self and instance vars

What's the correct way to reference 'self' (and ivars) within blocks without the block creating a strong reference (and thus incrementing the ref count)?

For instance, I've found the following increments the ref count for 'self':

^(id sender) {
    [self.navigationController popViewControllerAnimated:YES];
}

In order to circumvent the above, I've been doing the following:

__weak WhateverController *weakSelf = self;
^(id sender) {
    [weakSelf.navigationController popViewControllerAnimated:YES];
};

And yes, I realize this is pseudocode.

Upvotes: 3

Views: 1008

Answers (2)

Jody Hagins
Jody Hagins

Reputation: 28339

Also, an indirect reference to self also creates a retain on self. For example, if _ivar were an instance variable, accessing it is an implicit reference to self so the following would also retain self.

^(id sender) {
    [_ivar popViewControllerAnimated:YES];
}

Furthermore, to expand on your weak example, it is OK to send a message to a weak reference. If it's nil, nothing will happen. If not, then the compiler will generate code that ensures the reference remains valid through the invocation of the method.

So, this is fine:

__weak Foo *weakSelf = self;
^(id sender) {
    [weakSelf.foo doSomething];
}

because foo will either be nil or if not, it is guaranteed to remain non-nil throughout the execution of doSomething.

However, the following would be inadvisable because self could go to nil in-between calls, which is probably not what you want:

__weak Foo *weakSelf = self;
^(id sender) {
    [weakSelf.foo doSomething];
    [weakSelf.foo doSomethingElse];
}

In that case, you probably want to create your own strong reference inside the block, so you have a consistent value throughout the execution of the block.

On the other hand, if you access iVars directly through a weak reference, you must do the weak-strong dance because this code:

__weak Foo *weakSelf = self;
^(id sender) {
    weakSelf->_foo = bar;
}

will blow up if weakSelf is nil.

Thus, in the last two situations above, you want to do something like:

__weak Foo *weakSelf = self;
^(id sender) {
    Foo *strongSelf = weakSelf;
    if (!strongSelf) return;
    // Now, do anything with strongSelf, as it is guaranteed to be around
}

Of course, the iVar situation is only a problem if you actually access iVars directly...

Upvotes: 10

Moshe Gottlieb
Moshe Gottlieb

Reputation: 4003

Apple's notation is sself but other than that - you're fine.
In a non arc project use the following code to prevent 'self' from being retained by the block:
__block id sself = self

Upvotes: 2

Related Questions