问题
I have a number of tasks I need to execute serially but the task includes next block in a completion block.
What is a good technique for doing these tasks one at a time, starting the next task after the current one completes its completion block?
Is there a technique other than a NSOperation subclass with a serial NSOperationQueue?
回答1:
Standard solutions:
NSOperationQueue
withmaxConcurrentOperationCount
of1
. You say you don't want to do that, but you don't say why. Serial queues are the most logical solution.For example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1; [queue addOperationWithBlock:^{ NSLog(@"Starting #1"); sleep(3); NSLog(@"Finishing #1"); }]; [queue addOperationWithBlock:^{ NSLog(@"Starting #2"); sleep(3); NSLog(@"Finishing #2"); }]; [queue addOperationWithBlock:^{ NSLog(@"Starting #3"); sleep(3); NSLog(@"Finishing #3"); }];
If you don't want a serial
NSOperationQueue
, you can use a standard concurrent queue, but just make each operation dependent upon the prior one. You'll achieve the serial behavior you're looking for without using a serial queue.For example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSOperation *operation; NSOperation *previousOperation; operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting #1"); sleep(3); NSLog(@"Finishing #1"); }]; [queue addOperation:operation]; previousOperation = operation; operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting #2"); sleep(3); NSLog(@"Finishing #2"); }]; [operation addDependency:previousOperation]; [queue addOperation:operation]; previousOperation = operation; operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting #3"); sleep(3); NSLog(@"Finishing #3"); }]; [operation addDependency:previousOperation]; [queue addOperation:operation];
You could also create a GCD serial queue with
dispatch_queue_create
. It achieves the same thing as the first option, except using GCD instead ofNSOperationQueue
.For example:
dispatch_queue_t queue = dispatch_queue_create("com.ConnerDouglass.operationtest", 0); dispatch_async(queue, ^{ NSLog(@"Starting #1"); sleep(3); NSLog(@"Finishing #1"); }); dispatch_async(queue, ^{ NSLog(@"Starting #2"); sleep(3); NSLog(@"Finishing #2"); }); dispatch_async(queue, ^{ NSLog(@"Starting #3"); sleep(3); NSLog(@"Finishing #3"); });
回答2:
I think this is an interesting solution: https://github.com/berzniz/Sequencer
回答3:
What about something like this:
-(void)start
{
// Start the async chain
[self performSelectorInBackground:@selector(action1) withObject:nil];
}
-(void)notifyDone:(NSNumber *)taskID
{
NSLog(@"Done with task #%i", taskID.intValue);
}
-(void)action1
{
// Do some fancy async stuff here
// Now, we are done. Notify the main thread that task 1 is complete.
[self performSelectorOnMainThread:@selector(nofityDone:) withObject:[NSNumber numberWithInt:1] waitUntilDone:YES];
// Move onto the next task once the main thread is done handling the notification
[self action2];
}
-(void)action2
{
// Do the same sort of thing as "action1" did, then call he next method
}
来源:https://stackoverflow.com/questions/15397848/serializing-asynchronous-methods