问题
In my code I want to handle operations individually in a queue and be able to pause and resume the operations operation in the queue. How can I implement that ?
Let me explain my question in brief, I have used below code for creating operation by subclass NSOperation and added this operation to NSOperationQueue.
@interface MyLengthyOperation: NSOperation
@end
@implementation MyLengthyOperation
- (void)main
{
// a lengthy operation
@autoreleasepool
{
for (int i = 0 ; i < 10000 ; i++)
{
// is this operation cancelled?
if (self.isCancelled)
break;
NSLog(@"%f", sqrt(i));
}
}
}
@end
I have created above operation and I am calling it with
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
myQueue.name = @"Download Queue";
myQueue.maxConcurrentOperationCount = 4;
[myQueue addOperation:operation];
Now I want to pause and resume my operation. Lets suppose that the loop is on 6786 and I pressed the pause button, then the queue should pause this operation and when I press start then it should start from 6786.
I want to control multiple operations in the queue. How can I do that ?
I looked at [queue setSuspended:YES];
- this will prevent the queue from adding new operations but I want to control existing operations in queue.
Waiting for your Answers.
Thanks in Advance !
回答1:
The is no in-built ability to pause a particular NSOperation, if you want this behaviour then you need to build it yourself.
You can use an NSCondition
to do this -
@interface MyLengthyOperation: NSOperation
@property (atomic) BOOL paused;
@property (nonatomic,strong) NSCondition *pauseCondition;
@end
@implementation MyLengthyOperation
-(instancetype) init {
if (self=[super init]) {
self.pauseCondition=[NSCondition new];
}
return self;
}
- (void)main
{
// a lengthy operation
@autoreleasepool
{
for (int i = 0 ; i < 10000 ; i++)
{
// is this operation cancelled?
if (self.isCancelled)
break;
[self.pauseCondition lock];
while (self.paused) {
[self.pauseCondition wait];
}
NSLog(@"%f", sqrt(i));
[self.pauseCondition unlock];
}
}
}
-(void)pause {
[self.pauseCondition lock];
self.paused=YES;
[self.pauseCondition signal];
[self.pauseCondition unlock];
}
-(void)resume {
[self.pauseCondition lock];
self.paused=NO;
[self.pauseCondition signal];
[self.pauseCondition unlock];
}
777441end
You can then say [myOperation pause]
and [myOperation resume]
回答2:
NSOperation
doesn't provide support for pausing operations out of the box, you will have to implement that yourself. One strategy to do this would be using a condition variable (see the answer by Paulw11). You could even use a single condition variable to control multiple operations at the same time.
But this approach can be problematic if you want to pause many concurrent operations. Each paused operation will block one thread. Using the condition variable ensures that those blocked threads don't use any CPU, but the memory for those threads cannot be reused. Depending on the number of paused threads and what else you want to do in the meantime this memory usage can be problematic. Apple lists that as something to avoid.
Another approach is to "split" the operation. So when you want to pause you first suspend the queue and then have each operation enqueue a new operation object that starts where it left off. This of course will require more involved changes.
In your example you would give your operation subclass a property firstNumber
and start your loop from that instead of at zero. Then at pause you'd create a new operation with the current loop index as the firstNumber and enqueue this.
This not only gives you the advantage of not blocking any threads while the queue is paused. And also with this possibility you could implement a persistent queue that saves the pending operations to disk and resumes them the next time the app starts.
来源:https://stackoverflow.com/questions/29040915/managing-multiple-operations-in-single-nsoperationqueue-ios-like-pause-resume-si