What happens when, during its execution, the parameter value is zero?

Suppose I have an object with a strong block reference. Sometime during the execution of this block, a strong reference is set to nil. Does the unit guarantee completion of its execution, or can it lead to a failure? I saw errors with incorrect access, but I can’t create them reliably, so I don’t know exactly why they appear.

For instance:

-(void)method { self.block = ^{ //code self.block = nil; //more code - crash here? } } -(void)otherMethod { block(); } 
+4
source share
3 answers

I believe that I finally have a satisfactory answer to this question. Note that this is all in the context of ARC.

A block may be freed during its execution. The block will continue to execute as usual, but any of its pointers to captured variables becomes suspicious (and potentially dangerous).

Suppose ObjectA has a copy-copy property called replenishment:

 @property (nonatomic, copy) void (^completion)(); 

... where the assignment looks something like this:

 __weak ObjectA * weakSelf = self; self.completion = ^{ weakSelf.completion = nil; [weakSelf doSomethingElse]; }; 

If the block is called like that ...

 -(void)method { _completion(); //directly uses ObjectA instance of the block } 

... then, assuming nothing else refers to this instance of the block, it is freed and its captured variable weakSelf becomes zero. doSomethingElse is never called. The best way around this is to simply call the block using its accessor - this will allocate a new copy on the stack. The original will be released, but the new copy and all its captured variables will be saved in the current context.

 -(void)method { self.completion(); //uses new copy of the block } 
+3
source

Documents do not guarantee that the block will be saved during its execution. Conversely, documentation for GCD calls, such as dispatch_async , makes such guarantees. From this, it seems you cannot assume that a normal call to a block will save it.

So, in your code, you probably want:

 -(void)otherMethod { dispatch_block_t localBlock = Block_copy(block); localBlock(); Block_release(localBlock); } 
+3
source

When the method executing the block does not check if there is still a reference to the block, a failure may occur. You may have had these method failures because there was no validation.

 - (void)methodWithBlock:(void (^)(void))block { if (block) // this check is to prevent crashes when calling to a released block pointer ... { block(); } } 

You may have come across code in which such a check was absent, which could lead to emergency situations that you experienced. Of course, I experienced the same thing.

+1
source

Source: https://habr.com/ru/post/1432385/


All Articles