3

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.

2 Answers 2

10

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

Sign up to request clarification or add additional context in comments.

1 Comment

In your second example, I think you mean [weakSelf.foo doSomething]; [weakSelf.foo doSomethingElse];
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.