iOS blocks and strong/weak references to self
You don’t need to make two sets of weak references. What you want to avoid with blocks is a retain cycle—two objects keeping each other alive unnecessarily.
If I have an object with this property:
@property (strong) void(^completionBlock)(void);
and I have this method:
- (void)doSomething
{
self.completionBlock = ^{
[self cleanUp];
};
[self doLongRunningTask];
}
the block will be kept alive when I store it in the completionBlock
property. But since it references self
inside the block, the block will keep self
alive until it goes away—but this won’t happen since they’re both referencing each other.
In this method:
- (void)doSomething
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self cleanUp];
}];
[self doLongRunningTask];
}
you don’t need to make a weak reference to self
. The block will keep self
alive, since it references self
from within, but since all we’re doing is handing the block off to [NSOperationQueue mainQueue]
, self
isn’t keeping the block alive.
Hope this helps.
iOS - GCD weak and strong reference to self
I was always using __weak references to self when I was in a block in
GCD. Everyone recommends that.
No. I don't know anyone that recommends that. Weak references make sense in some situations where there would be retain cycles. But whether a block should capture a weak or strong reference to any object (including the one self
points to) depends on the particular memory management design of the code in question and
I know that strong reference to self (tested) in GCD can't produce
retain cycles.
Passing a block to dispatch_async
on a global or main queue will NEVER produce a retain cycle.
Now if I refer directly to self (without __weak or __strong) I have
the exact behaviour with Test 2.
Maybe you don't see any difference in this case. But they have different behavior in general. Basically, your question is what is the difference between the block capturing a strong or weak reference to the object pointed to by self
.
The difference is in what happens, if the current object (object pointed to by self
) has been released by every other object that holds a strong reference to it, except potentially the block, and the block is executed afterwards asynchronously.
- If the block captured a strong reference to the current object, then that reference would keep the object alive during this whole time. So the object is still alive and we can use it and send messages to it, etc.
- If the block captured a weak reference to the current object, then the current object has already been deallocated, when the last strong reference to it was released. So the block's weak reference would be
nil
at this point, and the block is not going to do anything with it (it is either going to checkstrongSelf
and return when it sees that it isnil
, or it will send messages tostrongSelf
which isnil
which does nothing).
So in one case stuff is done and in the other case nothing is done.
If the current object in your case is some UI element, like a view or view controller, then as long as it is in the view hierarchy, it is going to be retained by things in the view hierarchy, so you need to exit out of this view/view controller in order to have the situation where nothing else has a strong reference to it.
In your case, all you do inside the block is [weakSelf.activityIndicator stopAnimating];
, i.e. a change to the UI. It doesn't matter whether this command is run or not, because, remember, the view containing this has already stopped displaying. Nobody can see this activity indicator. So what difference does it make if you stop it or not? But this is specific to this case. In general, you can imagine that the command inside the block changes some global state, or sends something over the network or something, where there is a big difference between if you do it or not.
Difference between weak references in a block and a NSTimer
The whole problem with the selector-based NSTimer
technique is that it establishes a strong reference to the object you pass to it. So whether the variable you used to hold the reference to the target you passed to scheduledTimerWithTimeInterval
was, itself, strong or weak, is immaterial. Assuming the target
reference wasn't nil
by the time the selector-based scheduled timer was scheduled, NSTimer
will establish its own strong reference. The "weak" vs "strong" nature of the references in calling code only dictates where ARC will place its own memory management calls in the caller's code, but the target
is just a simple pointer, and none of this weak vs strong information is conveyed to NSTimer
. The selector-based NSTimer
will establish its own strong reference that is not resolved until the timer is invalidated
.
This is why, when we want to invalidate a timer built via the selector-based method, we have to it in viewDidDisappear
or the like, rather than dealloc
.
Note, scheduledTimerWithTimeInterval
now has a block-based variation for iOS 10 and later, so you can enjoy the weak reference pattern of blocks if you don't have to support earlier iOS versions:
typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:30 repeats:true block:^(NSTimer * _Nonnull timer) {
// use weakSelf here
}];
Breaking retain cycle with strong/weak self
Any non-weak object that you reference inside the block will result in an implicit retain on that object, as the block is being created. Not executed, but created.
If you initialised the inner strongSelf directly from self, you will retain the value of self and potentially cause a retain cycle.
On the other hand, if you initialise it from weakSelf, you will not retain the value of weakSelf.
This is the reason for the two-step. The outer code copies the value of self into weakSelf, but ARC does not add a retain because it is __weak().
The block "creation" copies the value of weakSelf (or at least, manages to makes its value available at execution time). You can't see where it copied it to, but it did.
At block "execution" time, the block copies the "value of weakSelf" (which will be nil if self has been dealloc'ed in the mean time) into strongSelf which ARC then applies a retain to. Thus, for the duration of the block, the object referenced by strongSelf will remain alive, if it was alive to begin with. If you had only relied on weakSelf, it could go nil at any time during the execution of the block.
Note that weak/strong pattern is belt-and-braces - many examples actually rely on the fact that the weakSelf will go nil, and the block will silently become a collection of no-ops (messages to nil).
Retain cycles typically only occur if (a) you keep a reference to the block in a self.property or (b) you hand the block off to some other object (notification manager, etc), and tell that other object to forget it in your dealloc; in both cases your dealloc will never be called while the block is alive.
When people say "the way to do this stuff is with the weak/strong pattern", they are assuming the worst possible scenario.
Strong reference to a weak references inside blocks
Imagine that the last remaining strong reference to self is held on a different thread to the one that your block runs on.
Now this happens:
__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
if (weakSelf != nil) {
// last remaining strong reference released by another thread.
// weakSelf is now set to nil.
[myArray addObject:weakSelf];
}
});
This will crash with an NSInvalidArgument exception for adding nil to an array.
Making the reference strong before use removes the potential race condition and ensures that the pointer will always point to the same object.
If you are 100% certain that an object will only ever be referenced by one thread, it isn't strictly necessary to do this. But it's bad practice to make that assumption.
Weak Self in Blocks
That check is unnecessary, and is giving you a false sense of security.
Here's the problem:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf) { return; }
// THE LINE OF INTEREST
[weakSelf doSomething];
});
At THE LINE OF INTEREST
, some other thread might clear the last strong reference to self
, at which point weakSelf
is set to nil. So the doSomething
message gets sent to nil, which is “safe” (it does nothing), but might not be what you expected!
It's worse if you want to take a different action when weakSelf
is nil, e.g.
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf) {
[weakSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});
In this case, between the time the block verifies that weakSelf
is not nil and the time it sends the doSomething
message, weakSelf
might become nil, and neither doSomething
nor doSomethingElse
will actually run.
The correct solution is this:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});
In this case, copying weakSelf
to strongSelf
(which is strong by default) is atomic. If weakSelf
was nil, strongSelf
will be nil. If weakSelf
was not nil, strongSelf
will not be nil, and will be a strong reference to the object, preventing it from being deallocated before the doSomething
message.
Preventing `self` from creating a strong reference in blocks
The error message is right. You have to do the "weak-strong dance". You are only doing half of the dance. Pass self
into the block as weak, but then immediately assign it, inside the block, to a strong reference (as in your edited "Would recasting to be the correct way?").
Always pass weak reference of self into block in ARC?
It helps not to focus on the strong
or weak
part of the discussion. Instead focus on the cycle part.
A retain cycle is a loop that happens when Object A retains Object B, and Object B retains Object A. In that situation, if either object is released:
- Object A won't be deallocated because Object B holds a reference to it.
- But Object B won't ever be deallocated as long as Object A has a reference to it.
- But Object A will never be deallocated because Object B holds a reference to it.
- ad infinitum
Thus, those two objects will just hang around in memory for the life of the program even though they should, if everything were working properly, be deallocated.
So, what we're worried about is retain cycles, and there's nothing about blocks in and of themselves that create these cycles. This isn't a problem, for example:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];
The block retains self
, but self
doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.
Where you get into trouble is something like:
//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);
//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];
Now, your object (self
) has an explicit strong
reference to the block. And the block has an implicit strong reference to self
. That's a cycle, and now neither object will be deallocated properly.
Because, in a situation like this, self
by definition already has a strong
reference to the block, it's usually easiest to resolve by making an explicitly weak reference to self
for the block to use:
__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];
But this should not be the default pattern you follow when dealing with blocks that call self
! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after self
was deallocated.
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
weak variable with a strong reference in a block: does not create a retain cycle?
When you create or copy a block (it could be copied when you, for example, schedule it to gcd), referenced variables are captured (unless declared with __block specifier). Strong references are retained, weak references are not.
When you create local strongSelf
variable it keeps self
alive while block executes (i.e. while it's not executed and sits in a property there's no strong reference). When you reference self
directly - self
is captured and retained, now it keeps self
while block is alive.
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf; // strong reference when block executes
[self foo]; // strong reference when block created/copied
strongSelf.textLabel.text = [result stringValue];
}];
}];
See the difference? If you kill all strong pointers to object with direct self
reference there is still one strong reference inside the block, the one which was captured and retained. At the same time local strongSelf
pointer only holds strong reference to self
while block is executed, so, if self
was already dead, weakSelf
would be nil and strongSelf
will get nil value.
In Objective-c blocks, do I need to pass weak/strong self to helpers?
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 */ };
Related Topics
iOS 8 Auto Cell Height - Can't Scroll to Last Row
Change Default Icon for Moving Cells in Uitableview
Detecting iOS Uidevice Orientation
Get MAC Address of Bluetooth Low Energy Peripheral in iOS
Creating PDF File from Uiwebview
How to Underline a Uilabel in Swift
Custom Uitableviewcell Selection Style
Uialertview/Uialertcontroller iOS 7 and iOS 8 Compatibility
Wkwebview Persistent Storage of Cookies
Detecting Whether or Not Device Support Phone Calls
iOS - Mkmapview Place Annotation by Using Address Instead of Lat/Long
Where to Remove Observer for Nsnotification in Swift
How to Compile for Arm Rather Than Thumb in Xcode 4
How to Use a Uisegmentedcontrol to Switch Views
Center Content of Uiscrollview When Smaller