Assign ivar in a block using a weak pointer

I have a read-only isFinished in an interface file:

 typedef void (^MyFinishedBlock)(BOOL success, NSError *e); @interface TMSyncBase : NSObject { BOOL isFinished_; } @property (nonatomic, readonly) BOOL isFinished; 

and I want to set it to YES in the block at some point later, without creating a save loop to self :

 - (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock { __weak MyClass *weakSelf = self; MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { [weakSelf willChangeValueForKey:@"isFinished"]; weakSelf -> isFinished_ = YES; [weakSelf didChangeValueForKey:@"isFinished"]; theFinishedBlock(success, e); }; self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property } 

I am not sure if this is the right way to do this. Will this code leak or break, or is this normal? Perhaps there is an easier way that I forgot?

+6
source share
2 answers

The rolling block variable may be zero, before calling or adding confirmation when the function starts, or may fail

Since you are not saving yourself, and we assume that you are doing some long task in the background thread by the time you run your code. weakSelf may be nil (I hope you use ARC and 5.0 so that you have leaked weak links).

If you do not have real weak links (<5.0, not ARC, the compiler will still take the value __weak, but it does not matter), this will lead to failure.

Also, accessing ivar using '->' will crash if the object pointer is zero, so you need to make sure that this does not happen.

Even if you make the code because dasblinkenlight wrote that it might crash if the weakSelf is currently zero, let's say you send the block to the background thread and then the object is freed before the block is executed, it makes weakSelf nil this way Using '->' will crash. In this case, I would modify the code as follows:

 __weak MyClass *weakSelf = self; MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { MyClass *strongSelf = weakSelf; //! whatever task you want executed strongSelf.isFinished = YES; theFinishedBlock(success, e); }; 

You can also check if weakSelf is equal to zero to prevent the execution of an expensive task if it does not make sense (the object is already destroyed). But it depends on the use case.

But there is another case that you need to consider when programming with blocks, for example: You may have an instance of a task object, which only role is to perform a task in the background, and in this case this code may fail, because that you will create a new task, and it will be possible to free it before the block runs in the background thread, in this case you must save yourself and do not save the block in the object (this will prevent the save cycle).

+5
source

A small workaround is to create a method and let the compiler process it for you. Works well, but I'm not sure if this is the right way. Can anyone tell if this is correct?

 __weak MyClass *weakSelf = self; MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { [weakSelf makeIsFinishedYes]; }; - (void)makeIsFinishedYes { isFinished_ = YES; } 
0
source

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


All Articles