First of all (and since this question has to do with memory management), I have to say I'm running on ARC.
I have an object (MyObject) which contains an array of MyProcess objects. MyObject, at a certain point, creates a new MyProcess, adds it to the array, gives it a completion handler in the form of a block, and then tells the process to start.
MyProcess* newProcess = [MyProcess new];
[allProcessesArray addObject: newProcess];
newProcess.completionBlock = ^(MyProcess* process){
[allProcessesArray removeObject: process];
// Other things are done here
};
[newProcess start];
Now, on MyProcess side of things, when start is called, MyProcess internally calls threadedStart (that runs on a background thread) which does its work and then calls the block when finished:
- (void)threadedStart
{
// Do something
dispatch_async(dispatch_get_main_queue(), ^{ self.completionBlock(self); });
}
The completion block is defined as a property in the interface of MyProcess in this way:
typedef void(^MyCallbackBlock)(MyProcess* process);
@property (strong) MyCallbackBlock completionBlock;
Now, MyProcess is only kept alive during its lifetime by allProcessesArray, since that array is the only object that has a reference to the process. When on the completion block I remove the process from the array, I reckon the process is immediately deallocked. Then, since the process contains the block itself, the block gets deallocked as well while it is still running!
I would expect this to cause problems, but I've tested this code and the block runs fine until the end. Now, there are two options: either my reasoning is wrong and this code is perfectly safe, or I'm right (or at least partially right) and this isn't safe as it only works sometimes.
Basically, my question is: is this approach to a callback block safe? And if not, can you suggest something different?