2013-03-13 93 views
4

我有许多任务需要串行执行,但任务包括完成块中的下一个块。序列化异步方法

什么是一次完成这些任务的好技术,在当前完成其完成块之后开始下一个任务?

是否有一种技术,而不是NSOperation子类与串行NSOperationQueue?

+0

他们全部NSOperations? – TheJer 2013-03-13 22:40:13

+0

你不想子类NSOperation吗?或者你有反对串行'NSOperationQueue'? – Rob 2013-03-13 22:55:34

+0

它们使用addOperationWithBlock作为块添加。异步方法不会等待,因此队列上的并发1不会执行任何操作。 – jarryd 2013-03-13 22:55:58

回答

6

标准溶液:

  1. NSOperationQueue1maxConcurrentOperationCount。你说你不想这么做,但你不知道为什么。串行队列是最合乎逻辑的解决方案。

    例如:

    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"); 
    }]; 
    
  2. 如果您不想串行NSOperationQueue,则可以使用标准的并发队列,但只是使每个操作依赖于前一个。您将在不使用串行队列的情况下实现您正在查找的串行行为。

    例如:

    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]; 
    
  3. 您还可以创建一个GCD串行队列dispatch_queue_create。除了使用GCD代替NSOperationQueue之外,它与第一个选项达到同样的效果。

    例如:

    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"); 
    }); 
    
+1

谢谢。问题是我使用addOperationWithBlock添加方法调用,但是因为它们是异步方法,所以即使并发性设置为1,也会出现“操作无法完成,打开的文件过多”的错误,块被标记为因异步呼叫未被等待而结束。 – jarryd 2013-03-13 22:55:13

+0

@ Helium3你可以用你调度到背景的代码的性质来更新你的问题吗?当排队的操作本身是异步的时候,有不同的方法,但是如果你可以更具体一些,这会有所帮助。在我的文件下载器类中,我将NSOperation子类化,并且在下载完成之前不要设置“isFinished”,但我不想继续猜测你想要做什么。 – Rob 2013-03-13 23:00:52

+0

@ Helium3除了子类化'NSOperation'和手工控制何时设置'isFinished'之外,您还可以为每个文件创建两个操作,一个是异步操作的开始,另一个是异步操作的完成处理程序。您可以根据前一个操作完成下一个操作。有关示例,请参阅http://stackoverflow.com/questions/14195706/multiple-locations-in-google-map-mkmapitem/14198584#14198584。 – Rob 2013-03-13 23:06:04

0

什么是这样的:

-(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 
} 
+0

谢谢,但这对于此解决方案并不实用。 – jarryd 2013-03-13 22:49:36