Referring to Weak Self Inside a Nested Block

Referring to weak self inside a nested block

It depends.

You only create a retain cycle if you actually store the block (because self points to the block, and block points to self). If you don't intend to store either of the blocks, using the strong reference to self is good enough --- block will be released first after it got executed, and then it will release it's pointer to self.

In your particular example, unless you're performing more operations which are not shown, you don't need to create any weakerWeakerEvenWeakerSelfs.

Use [weak self] in the nested block in swift

If you don't use [weak self], then for the life time of that block, you can have a circular reference between it and the object self refers to, when an object loses a reference to it, its reference drops by one, when it reaches zero then it is deallocates and reduces the reference count of any object it has a reference to. If you have a circular reference then neither are going to reach zero, because neither is going to get to zero to deallocate itself and reduce the reference to the other. For regular objects this is a problem because they will never be deallocated, for block though, it can depend on how they are used, if they are passed to a function that uses them straight away, then once they are executed they will be deallocated, and any circular references will be cut, it may be even beneficial that whilst your block is executing that it and self can't go away, but if the block is retained as an instance variable to be called, then you have a circular reference that will never go away. The way to deal with is is to use [weak self], saying references to self are weak in this block, you can then just deal with that on each time you use it, self?.myFunction() for example, or you can create a strong reference at the beginning, it used to be you used to have to use a different variable to self, but now you can go

guard let self = self else { return }

one of the good things of doing it this way, you are saying if it gets this far I want the block to execute completely, you have created a circular reference for the execution of the block and it will not go away until the block finishes executing. For example if you have a few functions starting with self?, then mid way through your block executing self could become nil, and only the first few functions are executed and the later are not.

Should I use weakSelf in nested blocks?

In this situation, you are not worried about cyclic references. What you are worried about is a situation where the object self isn't actually needed anymore, but using self inside a nested block would keep it unnecessarily alive. For example, if you have a view controller that should go away when the view is removed by the screen, but you download an image that you would like to display in the controllers view. If the image arrives long after the view is already gone, you don't want the view controller alive anymore.

Best is

__weak typeof (self) weakSelf = self;

before calling the outermost method. Then within every block that ought to use self, you add

typeof (self) strongSelf = weakSelf;

and use strongSelf within that block. Depending on the situation, you might want to check that strongSelf isn't nil at that point, but sending messages to strongSelf when it is nil has no effect, so if all you do is sending messages and getting or setting properties, then a check for nil is not necessary.

What happens if you don't do this? The difference will be that self may be kept alive unnecessarily into the innermost block, if you use self everywhere (or just in the innermost block).

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

break retain cycle in a block nested in another block

I think you can just create new strong reference inside nested block, like this:

- (void)test {
__weak typeof(self) weakSelf = self;
[self.viewSource fetchData:^(BOOL succeed, NSError * _Nonnull error, id _Nonnull data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf.dataSource disposalData:^{
__strong typeof(weakSelf) strongSelf = weakSelf; // <- new strong ref
[strongSelf updateUI];
}];
}];
}

It will override the first strongSelf in the nested block scope. And it will be only alive during the execution of the nested block without strong reference cycle created. I think so =)

Do we need to repeat `guard let self = self else { return }` inside each nested closure to keep strong self?

Yes, one is enough.
If you write

guard let self = self else { return }

you'll create a new local variable that will hold a strong reference to the outside weak self.

It's the same as writing

guard let strongSelf = self else { return }

and then use strongSelf for the rest of the block.

When to weak and when to strong reference for nested block in block

You do need a weak reference for the cell completion handler, because you have a reference cycle: self > UITableView > UITableViewCell > self.

You do not need to use the __strong qualifier. Variables are strong references by default.

You do not need a weak reference for the animation and transition completion handlers, as those blocks are released as soon as the transition completes, but in this case they can't use self because they're nested inside of a block that can't capture self.

So keep weakSelf and strongSelf, and use the same strongSelf variable inside all of the nested blocks.

Swift guarding weak self for nested callbacks

I think most part in @Andriy's answer is correct. But the most correct answer is that we don't even need to put [weak self] in any nested blocks.

When I first heard this from my colleagues, I don't want to buy it. But the truth is that, the first block defines the captured self to be weak and this captured self will be affecting all the captured self within current scope, in other words, within first block's {}. Therefore, there is no need to apply [weak self] any more if we have done it in the first most layer of callback.

It is very hard to find the exact document from Apple to prove this but the following code snippet with core foundation retain count CFGetRetainCount() it can prove that's true.

class TestClass {
var name = ""
var block1: (()->Void)?
var block2: (()->Void)?

func test() {
print(CFGetRetainCount(self))
self.block1 = { [weak self] in
self?.block2 = { // [weak self] in
print(CFGetRetainCount(self))
}
self?.block2?()
print(CFGetRetainCount(self))
}
self.block1?()
print(CFGetRetainCount(self))
}

deinit {
print(CFGetRetainCount(self))
}
}

do {
let tstClass = TestClass()
print(CFGetRetainCount(tstClass))
tstClass.test()
print(CFGetRetainCount(tstClass))
}

If you are interested, you can try this in your playground, feel free to remove the comment for the [weak self] for block2, you will see the same answer.

Retain count is always 2 and deinit is called correctly.



Related Topics



Leave a reply



Submit