Примите меры, когда два отдельных 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, но никогда не оба и всегда один. Это также не дает возможности отмены или возможности самостоятельно ограничить степень параллелизма. Но вы можете сделать это с минимальными изменениями кода.Второй подход заключается в замене асинхронных запросов синхронными, что позволяет использовать стандартную логику
NSOperationaddDependency: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(как показано в предыдущем пункте), чтобы сделать вашу третью операцию зависимой от двух других окончаний. Дополнительные сведения см. В разделеконфигурирование операций для параллельного выполнения руководства по программированию с параллелизмом .