Ответ 1
Когда у вас есть асинхронные задачи с зависимостями, у вас есть несколько вариантов:
-
Простейшим решением с наименьшими изменениями кода является использование семафора:
// create a semaphore dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // initiate two requests (signaling when done) [self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results) { [self.refreshControl endRefreshing]; dispatch_semaphore_signal(semaphore); } onFailure:^(NSError *error) { [self.refreshControl endRefreshing]; dispatch_semaphore_signal(semaphore); }]; [self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results) { [self.refreshControl endRefreshing]; dispatch_semaphore_signal(semaphore); } onFailure:^(NSError *error) { [self.refreshControl endRefreshing]; dispatch_semaphore_signal(semaphore); }]; // now create task to to wait for these two to finish signal the semaphore dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // wait for the two signals from the two fetches to be sent dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // now do whatever you want when those two requests finish // if you need to do any UI update or do any synchronizing with the main queue, just dispatch this to the main queue dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"all done"); }); });
Этот подход может быть проще всего, но влечет за собой всевозможные ограничения. Например, это свяжет рабочий поток, ожидающий, пока другие два отправят сигнал, поэтому вам нужно быть уверенным, что у вас не будет слишком много таких коллекций запросов, идущих одновременно. Вы также должны быть уверены, что эти запросы вызовут либо
onSuccess
, либоonFailure
, но никогда не будут оба и всегда одни. Это также не дает возможности отмены или возможности ограничить степень concurrency самостоятельно. Но вы можете сделать это с минимальными изменениями кода. -
Второй подход заключается в замене ваших асинхронных запросов синхронными, которые затем можно использовать логику
NSOperation
standardaddDependency
:NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ // completion operation }]; NSOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ // do fetch1 _synchronously_ }]; [queue addOperation:operation1]; NSOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ // do fetch2 _synchronously_ }]; [queue addOperation:operation2]; [completionOperation addDependencies:@[operation1, operation2]]; [queue addOperation:completionOperation];
Этот подход требует, чтобы ваши синхронные выборки были потокобезопасными. Я не знаком с этим API, который вы используете, поэтому я не могу говорить с этим.
-
Если у вас нет синхронных исполнений ваших запросов на выборку, которые вы могли бы добавить в очередь, третий подход заключался бы в том, чтобы обернуть ваши запросы асинхронной выборки с вашим собственным параллельным подклассом
NSOperation
, который не будет сигнализироватьisFinished
до тех пор, пока не будет выполнена асинхронная операция (а также предположительно вызовите свои собственные блокиonSuccess
иonFailure
). После этого вы можете использовать функциональностьsetDependency
(как показано в предыдущей точке), чтобы сделать вашу третью операцию зависимой от двух других финишей. Для получения дополнительной информации см. Раздел Настройка операций для параллельного выполнения в руководстве по программированию concurrency.
Мне хотелось бы дать более окончательный ответ, но я недостаточно разбираюсь в параметрах/ограничениях, связанных с вашей параллельной управляемой контекстной библиотекой.