Strong Reference to a Weak References Inside Blocks

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

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.

Strong reference in the block, it will be retained?

There are two reasons to capture weak references within a block.

  1. avoid retain cycles

  2. create no-op situations.

The former has been discussed ad-nauseum. The second is more interesting.

Example

The block in question is a completion handler for an image download. When the download is complete, it is to be displayed in an image view.

It doesn't need to do anything if the image view has already been deallocated (say the user has switched to a new view). There is no danger of a retain cycle, because the image view has no reference to the block. However, capturing a weak reference allows the image view to be deallocated before the block executes. Thus, if the user switches views before the image is downloaded, the block ends up doing nothing because its weak reference has already been niled. It also doesn't matter if the image view is deallocated part way through the block's execution, because it just turns operations on the image view into no-ops, instead of turning the entire block into a no-op.

Sometimes, however, the block wants the no-op behavior, but only if the reference was already nil when it began (or reached a certain point in the code path). If, at the time the block executes, the object is live, the block has to execute in its entirety. It can't stop half-way through because the object is deallocated on some other thread.

Example

The purpose of the completion block is to add a caption, defined by a string, to the image. If the string has been deallocated already, no caption is to be added. However, if the string is still live when post-processing begins, it must remain live to avoid trying to create an attributed string with a nil reference, because that leads to a crash.

In this scenario, it would be proper to capture the string with a weak reference, so it can be deallocated by some other thread (leading to no caption). However, before the string is used within the block, it must be captured strongly to avoid a crash when creating the attributed string.

Weak/Strong reference within nested blocks

(@trungduc was close to an answer but unfortunately has decided to delete it. So now as I may have inadvertently helped lose you your only answer to date I'll see if I can help you out.)

This answer only applies when using ARC

What are the difference between:

The probably surprising answer is that in this particular example not a lot...

When Objective-C makes a method call on an object it ensures that the object is alive across the call. So in the call:

[weakSelf.networkCall_2 completionHandler:^(id response2) {...}];

which is shorthand (using dot notation) for:

[[weakSelf networkCall_2] completionHandler:^(id response2) {...}];

First weakSelf is loaded and a strong reference held to the result, call this reference A. Then the property (method) networkCall_2 is called on A and a strong reference held to its result, call this B. At this point the compiler is free to drop the strong reference A as it is not used passed this point. Finally the call to the method completionHandler: on B is called. After that returns, which may be before the passed completion block has been invoked, the compiler is free to drop the strong reference B.

If A or B is nil above then the calls on them simply return nil and nothing much happens.

Note: your code is a little unusual, more common might be something like:

[weakSelf networkCall_2:<some argument> completionHandler:^(id response2) {...}];

that is networkCall_2:completionHandler: is a method on the object referenced by weakSelf. If this is what your actual code looks like then the above still applies and the compiler will hold a strong reference across the call to whatever weakSelf references.

Turning now to:

__typeof__(self) strongSelf = weakSelf;
if(response) {
[strongSelf.networkCall_2 completionHandler:^(id response2) {...}];

The compiler first loads weakSelf and holds a strong reference to it in strongSelf. Then the property (method) networkCall_2 is called on strongSelf and a strong reference held to its result, call this B. At this point the compiler is free to drop the strong reference strongSelf as it is not used passed this point. Etc.

(Note: "free to drop" in both cases above does not mean the compiler will immediately drop it, it may defer that until the end of the if or block.)

Notice the similarity in the two descriptions? In this particular example there is really no difference between using weakSelf and strongSelf. So why does some code use the strongSelf pattern? Consider:

__typeof__(self) strongSelf = weakSelf;
if (strongSelf) // object still exists)
{
// *all* three methods will be called
[strongSelf method1];
[strongSelf method2];
[strongSelf method3];
}

vs:

[weakSelf method1]; // call method1 if weakSelf is not nil
[weakSelf method2]; // call method2 if weakSelf is *still* not nil
[weakSelf method3]; // call method3 if weakSelf is *still* not nil

Using the strongSelf pattern above ensures that either 0 (if weakSelf is nil) or 3 method calls are made. If the weakSelf pattern is used 0, 1, 2 or 3 methods may be called.

Your particular example has the same result either way as there is only one use of strongSelf/weakSelf, in the above the result can differ as there are multiple uses of strongSelf/weakSelf.

Which leaves us with your question:

Also, what happens if networkCall_2 is running, and self gets deallocated? Does it finish or terminate the call?

This question reads as though networkCall_2 is a method not a property, see the note above, we'll cover both cases:

  1. If here you are referring to the self of the method networkCall_2 then as covered above Objective-C will keep a strong reference across the call to any object a method is invoked on, so self cannot be deallocated during a call. So an active call is never terminated due to its self disappearing.

  2. If your networkCall_2 is indeed a property as shown then the object referenced by weakSelf (the A above) will not be deallocated across the property call, as in (1). However when then calling the completionHandler: method on whatever object the property call returned (the B above) then A could be deallocated across that call (unless that call holds a strong reference to A by other means).

Hope I understood your question correctly and if so I think your answer boils down to knowing:

An object on which a method (or property) is called will not be deallocated during that method (or property) call.

HTH

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
}];

Why passing a weak reference to a block prevents an object from being retained?

You can sort of think of a block as an object which has an "instance variable" for each captured variable, which is initialized with the value of the corresponding captured variable at the time the block is created.

In ARC, the block's "instance variables" have the same ownership specifier as the corresponding captured variable. So if a captured variable of object-pointer type is __strong (the default), the block's "instance variable" is also __strong, so it retains the object pointed to for the lifetime of the block. If a captured variable of object-pointer type is __strong, the block's "instance variable" is also __weak, hence it is a zeroing weak reference to the object pointed to.

Blocks and objects with Strong Reference Cycle?

None of those are correct.

There are just two objects here. An Employee object. And a block. That's it.

You didn't show what myBlock is declared as, but assuming that it's an instance variable of Employee, then yes, by that assignment, the Employee object has a strong reference to the block.

The block has a weak reference to the Employee object, because it captures the local variable weakSelf from the surrounding scope, and by capturing it, it makes an implicit "instance variable" in the block that has the same memory management characteristics as the captured variable (in this case, weak).

The strongSelf inside the block is not relevant. It is just a local variable. Local variables are not instance variables, so they are not part of one object referencing another. Local variables only live for the duration of a particular invocation of the function. They do not cause cycles.

The reason for innerSelf was so that the object pointed to (by weakSelf, which is the same object pointed to by self and innerSelf) is not deallocated in the middle of the function. This is only a problem if you were going to use weakSelf multiple times in the function, and rely on the states from those times to be consistent. By using innerSelf, it will make it consistently pointing to an existing object, or consistently nil. Since you only use weakSelf once here, it is not necessary.

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.

strongSelf pointing to weakSelf in a block, why?

Edit: Updated to better reflect actual system semantics (as pointed out by Darren).

By using weakSelf in the block, you are avoiding retain cycles. If you were to replace the block code with [weakSelf timeout], there would be no difference; the object is retained for the duration of the timeout execution.

If you had instead used __unsafe_unretained to create your weakSelf, it's possible that the machine could release the memory back to the system and cause your app to EXC_BAD_ACCESS while executing timeout. Creating a strong reference in this instance would avoid this error.


When you create a strong reference, it is held within its scope; in this case, for the duration of the block. Because your block only effectively executes one statement, the replacement to [weakSelf timeout] causes no harm. If you had multiple statements that all used weakSelf or relied on the state of weakSelf, then you would want to create a strong reference for the scope of all of the statements.



Related Topics



Leave a reply



Submit