Should I use weakSelf in nested blocks?

I am trying to correctly avoid holding loops with blocks in Objective-C and am not sure if nested blocks are.

If I write a simple block as follows:

[self doSomethingWithBlock:^{ [self doSomethingElse]; }]; 

The compiler catches and warns me that this can lead to save cycles. I modify it as follows to avoid a loop:

 __weak __typeof(self)weakSelf = self; [self doSomethingWithBlock:^{ __strong __typeof(weakSelf)strongSelf = weakSelf; [strongSelf doSomethingElse]; }]; 

When I write something like this:

 [self doSomethingWithBlock:^(MyObject* object){ [object doSomethingElseWithBlock:^{ [self doYetAnotherThing]; }]; }]; 

The compiler is happy, but I'm not sure that it is safe. Despite the fact that there is an intermediate object between them, it still looks conceptually the same as above, but now it saves a loop with 3.

Should this be so?

 [self doSomethingWithBlock:^(MyObject* object){ __weak __typeof(self)weakSelf = self; [object doSomethingElseWithBlock:^{ __strong __typeof(weakSelf)strongSelf = weakSelf; [strongSelf doYetAnotherThing]; }]; }]; 

Or how is it?

 __weak __typeof(self)weakSelf = self; [self doSomethingWithBlock:^(MyObject* object){ [object doSomethingElseWithBlock:^{ __strong __typeof(weakSelf)strongSelf = weakSelf; [strongSelf doYetAnotherThing]; }]; }]; 
+6
source share
4 answers

In this situation, circular links do not bother you. What is bothering you is the situation where the ā€œIā€ object is actually no longer needed, but using the ā€œIā€ inside the nested block will save it unnecessarily. For example, if you have a view controller that should disappear when the view is deleted by the screen, but you upload the image that you want to display in the view of the controllers. If the image arrived too long after the view has already disappeared, you no longer want the view manager to be alive.

The best

 __weak typeof (self) weakSelf = self; 

before calling an external method. Then in each block that self should use, you add

 typeof (self) strongSelf = weakSelf; 

and use strongSelf in this block. Depending on the situation, you may need to check that strongSelf is not zero at this point, but sending messages to strongSelf when it is zero does not affect it, so if everything you do sends messages and receives or sets properties, then verification for nil is not required.

What will happen if you do not? The difference is that the self can be saved without the need for the inner block, if you use yourself everywhere (or only in the inner block).

+4
source

You should not grab something weak because you get a warning from the compiler; compiler warning just wonders; he does not know how the methods you call make references. You should only do this if you understand the link architecture and determine that a loop exists and determine that capturing a weak link instead preserves intentional behavior. You did not give us the -doSomethingWithBlock: code. This would create a save loop if inside this method it assigns a block to a property variable or an instance of self . Does it do it or not? If not, then there is no hold cycle, and it makes no sense that the external block does not commit self .

Assuming that the capture of the external block of self is weak, examples in which the external block of capture of self out of the question. The rest of the questions are whether the internal block should capture self (or any other version of self , such as strongSelf ). In other words, will you do something like this:

 __weak __typeof(self) weakSelf = self; [self doSomethingWithBlock:^(MyObject* object){ __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [object doSomethingElseWithBlock:^{ [strongSelf doYetAnotherThing]; }]; } }]; 

or something like this:

 __weak __typeof(self) weakSelf = self; [self doSomethingWithBlock:^(MyObject* object){ __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [object doSomethingElseWithBlock:^{ __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [strongSelf doYetAnotherThing]; } }]; } }]; 

Again, the main problem to determine is whether there is a save cycle if the inner block strongly fixes self . There will only be a save loop if [object doSomethingElseWithBlock:... somehow assigns the block to a property variable or an instance of self . But how could this be? The method is called on object , not self . The method does not get self any way. Unless something complicated happens, the method will not assign a variable to the property or instance self , so it is unlikely that a save loop will be created. This means that locking the inner self block is not weakly required to prevent a save cycle.

But whether the internal block can fix self weakly or strongly affect behavior. Namely, if the inner block weakly fixes self , self can be released by the time the block starts, in which case [strongSelf doYetAnotherThing]; will not be executed, whereas if the internal block captured self strongly, it would keep self live and [strongSelf doYetAnotherThing]; will be executed. So it depends on what -doYetAnotherThing does. If it performs some kind of user interface operation on self , which is a user interface representation or something like that, then whether you perform it in a view that is no longer displayed does not matter. But if he, for example, sends something to the network or something like that, then regardless of whether it is being executed, it can make a big difference.

+1
source

See the answer to this question.

I would do it

 __weak typeof (self) weakSelf = self; [self doSomethingWithBlock:^(MyObject* object){ [object doSomethingElseWithBlock:^{ [weakSelf doYetAnotherThing]; }]; }]; 
0
source

Xcode 8 beta 4 emphasizes the self keyword and warns of a possible save loop for use inside a block.

Programming with Apple Developer Connection in Objective-C (Work with blocks):

Avoid strong support cycles when capturing yourself. If you need to capture yourself in a block, for example, when defining a callback block, it is important to consider the consequences of memory management.

Blocks support strong references to any captured objects, including self, which means that it is easy to end with a strong loop reference if, for example, the object supports the copy property for a block that captures itself:

 @interface XYZBlockKeeper : NSObject @property (copy) void (^block)(void); @end @implementation XYZBlockKeeper - (void)configureBlock { self.block = ^{ [self doSomething]; // capturing a strong reference to self // creates a strong reference cycle }; } ... @end 

The compiler will warn you of a simple example like this, but a more complex example may include some strong links between objects to create a loop, which makes diagnosis difficult.

To avoid this problem, its best practice is to capture a weak link to yourself, for example:

 - (void)configureBlock { XYZBlockKeeper * __weak weakSelf = self; self.block = ^{ [weakSelf doSomething]; // capture the weak reference // to avoid the reference cycle } } 

By capturing a weak pointer to itself, the block will not maintain strong communication with the XYZBlockKeeper object. If this object is freed before the block is called, the weakSelf pointer will simply set to nil.

This site is reportedly providing a means to facilitate the creation of the self keyword when used inside a block; it also contains instructions for returning a weak self object or a class that was previously strong, strong:

https://coderwall.com/p/vaj4tg/making-all-self-references-in-blocks-weak-by-default

0
source

All Articles