Objective-C proper use of blocks with ARC? - objective-c

I know this question has been asked before, but non of the solutions solve my problem, so I'm asking this again. I am trying to call a method on self as the result of a callback through a block. I'm getting the following error:
Capturing 'self' strongly in this block is likely to lead a retain cycle
- (void)viewDidLoad {
[super viewDidLoad];
self.webClient.completionHandler = ^{
[self populateData];
};
}
I tried doing something like the code below, and I'm still getting the same warning.
What's the solution?
__weak id myself = self;
[myself populateData];

Your code should look like this:
- (void)viewDidLoad {
[super viewDidLoad];
__weak id weakSelf = self;
self.webClient.completionHandler = ^{
[weakSelf populateData];
};
}

UIAdam gave the correct answer, but it's worth understanding why it is correct.
First, why did you get the warning?
self has a strong reference to webClient. webClient has a strong reference to completionHandler. completionHandler has a strong reference to self. So if all other references in your program go away, there is still a strong reference to each item in this cycle, so they can never be deallocated.
The attempt of writing
__weak id myself = self;
[myself populateData];
doesn't work of course. The block still references self because it is assigning it to myself. So no difference here.
UIAdam's solution of writing
__weak id weakSelf = self;
self.webClient.completionHandler = ^{
[weakSelf populateData];
};
means that weakSelf is a weak reference, and the block only contains a weak reference to self. So if all other strong references to self is gone, there's only a weak reference left. A weak reference doesn't keep self alive, so self gets deallocated.
Now what if that happens, but something else had a strong reference to webClient and your block is called? weakSelf is a weak reference, and weak references are set to nil when the object is deallocated. So you have to be prepared that weakSelf is nil when your block gets called. It is actually better to write
id strongSelf = weakSelf;
[strongSelf populatedData];
inside the block: strongSelf might be set to nil, or it will be set to self. But since it is a strong reference, it will stay non-nil until the block has finished. If it was not nil to start with.

Related

In Objective-c blocks, do I need to pass weak/strong self to helpers?

Within blocks, do I need to pass some version of self to helper methods?
In this example, publicMethod() is calling _privateHelper using strongSelf.
But, _privateHelper() is calling _secondPrivateHelper() using self. Is this fine or should I pass down strongSelf to the helpers?
- (void)publicMethod
{
auto __weak weakSelf = self;
dispatch_sync(dispatch_get_main_queue(), ^{
auto __strong strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[strongSelf _privateHelper];
});
}
- (void)_privateHelper
{
[self _secondPrivateHelper]; // <-- what version of `self` is sending the message here? I'm assuming the copied `strongSelf` from above.
}
- (void)_secondPrivateHelper
{
NSLog(#"Hello, World");
}
TLDR
When to use strong or weak depends on how you use the block. In your code strong and weak does not really matter but I will give an example where it matters and explain how to then use weak.
I think you are considering the wrong things here. In your example all pointers to self can (and should) be strong. You do not need to dance the dance here and you should consider using weak only when you create retain cycles which I will discuss in a moment.
In your case note that when you are inside the block you want a strong pointer to self. If you have a weak pointer the block becomes superfluous when self is nil. To get a strong pointer simply change your block to
... ^{
[self _privateHelper];
});
rather than the way you do it. Now (and in your original code) you have (and should have) a strong pointer to self inside both your _privateHelper and _secondPrivateHelper.
But this is not the issue.
Retain cycle
Suppose you have an ivar
#property (strong,nonatomic) void ( ^ block )( void );
Only now do you have potential trouble and you probably need to use weak pointers. The reason being that if somewhere in your code you have
self.block = ^{ [self _privateHelper]; };
the block will retain a strong pointer to self. At the same time, self is keeping, through the ivar, a strong pointer on the block. Can you see the retain cycle? Neither the block nor self will ever be released automatically as both are keeping strong references to the other.
Fixing it
You can change the ivar to weak in which case you break the cycle. If the block goes out of scope the weak ivar goes to nil and there is no retain on self.
You could also do
self.block = ^ { [weakSelf _privateHelper]; };
inside the block to break the cycle. Now if self goes out of scope the block no longer has a hold on it and again there is no retain cycle on self.
Both these fixes are used - a lot of ivars will be weak in a UI environment to prevent the e.g. label keeping a strong reference on the vc while the vc also keeps a strong reference on the label.
When working with blocks you typically use weak pointers to self inside the block only if you potentially have a retain cycle. This is often not an issue and in your code also is not an issue as self does not retain the block. So in general your helper blocks could probably get away with strong pointers to self. You only need to dance the dance if somehow self and the block are creating a retain cycle.
Finally, a third way to fix it is to set the ivar to nil yourself. So you could have code that looks like this
if ( self.block )
{
self.block (); // Execute block
self.block = nil;
}
This also makes sense sometimes e.g. when you want to retain the block and self until the block executes. Here you release the ivar manually by setting it to nil after which it no longer retains self and the cycle is broken albeit manually.
You could even do this inside the block, e.g. change the block to
self.block = ^ { [self _privateHelper]; self.block = nil; /* release when done */ };

Using an ivar inside a method which is called from a block

I want to use an ivar in a method that is being called from a block. Is it fine to call the ivar directly from it without causing a retain cycle?
I have seen other questions related to calling properties- saying that we 'can' use self. Just wanted to make sure about ivars, can we call ivar directly or do we need to use self->_myInstanceVariable explicitly?
__weak MyClassName *weakSelf = self;
[MyBlockCreator myBlock:^{
MyClassName *strongSelf = weakSelf;
[strongSelf doSomething];
}];
- (void) doSomething {
_myInstanceVariable = someObject
// is it fine to use the ivar directly above?
// or do we want use self explicitly?
// like self->_myInstanceVariable
}
In this case you don't need to make the reference weak/strong at all, the only situation in which you can cause a retain cycle is if self references a block and a strong version of self is captured within that block. Since self doesn't retain the block in question, there would be no retain cycle even using a strong reference.
[Foo doWithBlock:^{
bar.baz = #"Hello World"; // Totally fine without weak/strong since bar doesn't retain the block here.
}];
In situations where self holds a strong reference to a block and the block refers to self, you need to make the reference weak outside the block then make it strong again inside.
__weak id weakSelf = self;
[self doWithBlock:^{
id strongSelf = weakSelf;
strongSelf.baz = #"Ok";
}];

Do methods called from within a block need to use weakSelf?

If the code inside a block calls a method, will a retain cycle exist if that method references self? In other words, does all code downstream of a block need to use the weakSelf/strongSelf pattern?
For example:
__weak __typeof__(self) weakSelf = self;
Myblock block = ^{
[weakSelf doSomething];
};
. . .
- (void)doSomething
{
self.myProperty = 5; // Is this ok or does it need to use a weakSelf?
}
Objective-C is not scoped like you suggest, namely, you don't have access to weakSelf from within -doSomething. Furthermore, as you are calling -doSomething on weakSelf, "self" within that call is actually referring to the same object that weakSelf is.
In short, no, you shouldn't, you can't and you shouldn't.
Retain cycle will be triggered only if you retain self inside the block. Otherwise it will just throw a warning only.
This is fine you can use this. Because block retains every vars used inside, so retain cycle would be like
Self would retain block
If block retains self then
Self would again retain block
block would retain self, so cycle goes on
The thing you are doing in method is just message passing. Everytime block is called a message would be sent to self to doSomething. And you can retain self in doSomething method it wont trigger retain cycle because this method dont have cycle loop to self. Hope you understand :)
- (void)doSomething
{
self.myProperty = 5; // Is this ok or does it need to use a weakSelf?
}
you can do this to get rid of retain cycle problem.
[self class] __weak *weakSelf = self;
self.completionBlock = ^{
[self class] __strong *strongSelf = weakSelf
[weakSelf doSomething];
};

Does declaring strongSelf from weakSelf before a block cause retain cycle

Here is the block in question. Im wondering if declaring strongSelf outside of the block will introduce a retain cycle in anyway. The reason for setting up the strongSelf outside the block is that I'm worried that weakSelf will be deallocated before the completion block.
__weak CollectionView *weakSelf = self;
CollectionView *strongSelf = weakSelf;
[self
performBatchUpdates:
^{
strongSelf->_cellSet = [strongSelf performDeletions:[strongSelf deletionsTowards:destinationSet from:strongSelf->_cellSet] from:strongSelf->_cellSet];
[(CollectionViewLayout *)strongSelf.collectionViewLayout setCellSet:strongSelf->_cellSet];
}
completion:
^(BOOL finished)
{
[strongSelf insertTowards:destinationSet];
}];
What you do is just pointless. weakSelf is a weak reference to self. strongSelf is a strong reference to self. It is captured by the block, so the block now also has a strong reference to self (that's the difference when you use weakSelf in the block: When the block captures weakSelf, the block has a weak reference to self). Instead of using strongSelf in the block, it would be much easier to just use self - it will be exactly the same thing. You might confuse the compiler enough to not give you any warnings when you use strongSelf where you would have got a warning for using self (if that warning was appropriate).
Whether you cause a retain cycle: Depends on the code. If a copy of the two blocks is stored in the object self and not set back to nil when the completion blocks are called, then you have a retain cycle. If the two blocks are not stored anywhere then the strong reference to self goes away eventually.
The method that actually works well is to assign weakSelf to a strong reference strongSelf inside each block. And then the first thing that you do is to test once whether strongSelf is nil. In that case you know that self has been deallocated, and you need to think about what actions you would want to do in that case.

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