Примите меры, когда два отдельных NSFetchRequests завершены
Я использую удаленную базу данных с основными данными, и когда я выполняю следующие запросы выборки, в зависимости от подключения к интернету, это может занять некоторое время. Я хотел бы отслеживать эти два запроса и, когда они будут завершены-успешно или неудачно-я хотел бы запустить другой метод.
FetchRequest 1:
[self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results) {
//Succcess
[self.refreshControl endRefreshing];
} onFailure:^(NSError *error) {
[self.refreshControl endRefreshing];
}];
FetchRequest 2:
[self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results) {
//Succcess
[self.refreshControl endRefreshing];
} onFailure:^(NSError *error) {
[self.refreshControl endRefreshing];
}];
Я хотел бы подождать, пока запросы fetch 1 и еще 2 оба завершены раньше вызов другого метода.
Могу ли я использовать NSOperationQueue
для мониторинга обоих блоков? Если нет, то как лучше всего узнать, когда оба блока завершены?
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
, но никогда не оба и всегда один. Это также не дает возможности отмены или возможности самостоятельно ограничить степень параллелизма. Но вы можете сделать это с минимальными изменениями кода.Второй подход заключается в замене асинхронных запросов синхронными, что позволяет использовать стандартную логику
NSOperation
addDependency
: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
(как показано в предыдущем пункте), чтобы сделать вашу третью операцию зависимой от двух других окончаний. Дополнительные сведения см. В разделеконфигурирование операций для параллельного выполнения руководства по программированию с параллелизмом .