NSOperation - Forcing an operation to wait others

2019-01-21 06:39发布

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.

7条回答
Fickle 薄情
2楼-- · 2019-01-21 07:44

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:

  • Create Operation A, set delegate
  • you cannot proceed, delegate method fires
  • the delegate creates a new operation B, creates a copy of operation A, sets the dependency such that A will wait for B's completion
  • then the delegate cancels the original op A

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.

查看更多
登录 后发表回答