I am trying to implement an operation queue and I have the following scenario:
NSOperation A
NSOperation B
NSOperation C
NSOperation D
NSOperationQueue queue
I start adding A
to queue
.
During the execution of A
I need to get some data from B
and I can't continue with A
until B
returns what I need.
The same situation will occur for B
depending on C
and for C
depending on D
.
To manage this, at each NSOperation
I have this code:
NSOperation *operation; //This can be A, B, C, D or any other NSOperation
[self setQueuePriority:NSOperationQueuePriorityVeryLow]; //Set the current NSOperation with low priority
[queue addOperation: operation]; //Add the operation that I want to the queue
while(!operation.isFinished && !self.isCancelled){} //I need to wait the operation that I depend before moving on with the current operation
[self setQueuePriority:NSOperationQueuePriorityNormal]; //After the while, the other operation finished so I return my priority to normal and continue
if(self.isCancelled){ //If I get out of the while because the current operation was cancelled I also cancel the other operation.
[operation cancel];
}
My problem is that when I have something like 3 or 4 NSOperations
waiting and executing the while(!operacao.isFinished && !self.isCancelled){}
my code just freeze because the NSOperation that is important to me don't get executed, even if it have higher priority.
What I tried
Adding dependency during execution time but since my NSOperation is already running I doesn't seems to have any effect.
Instead of adding the operation to queue, I can do something
[operation start]
. It works, but canceling the current operation will also cancel the other operations that I started?I can do something like
while(!operacao.isFinished && !self.isCancelled){[NSThread sleepForTimeInterval:0.001];}
. It works, but is this the correct way? Maybe there is a better solution.
In this situation how I can guarantee that the operation that I want will run and the others will wait in background? What is the correct way to solve this?
If anyone question me why I don't add the dependency before starting my queue its because an operation will need the other only if some conditions are true. I will know if I need other operation only during execution time.
Thanks for your time.
Once an NSOperation is in its main method you have to go through with it. There is no paused state, only finished or cancelled.
I would implement a NSCopying on operation A which would copy the entire state into a new instance. You would have a delegate method or block which is able to communicate that this operation cannot go through because it is missing info from operation B.
So the process would go such:
Inside the delegate you have to make sure to suspend the queue to avoid a race condition. After the above steps you resume the queue. In operation A you would have multiple places where you check for isCancelled to actually not do any more work in main when it has been cancelled.