iOS Blocks and Strong/Weak References to Self

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 check strongSelf and return when it sees that it is nil, or it will send messages to strongSelf which is nil 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



Leave a reply



Submit