0

У меня есть класс модели DataFetcher, который извлекает данные через веб-службу, а затем сохраняет данные в хранилище данных Core Data, а затем обновляет ViewController с помощью методов делегирования. Вот нормальная последовательность (которая работает должным образом) без использования NSOperation:Непонимание последовательности NSOperationQueue

NSArray *serviceQueryResult = [self queryServiceFor:@"car"]; 
[self setData:serviceQueryResult]; 
[self persistData:_data]; 
[_loadDelegate updateCount:_data.count]; 
[_loadDelegate receivedData:_data]; 

Мне нужно поместить вызов веб-службы и вызов обновления базы данных на фоне потока. Мои мысли - создать NSBlockOperation, чтобы вызвать вызов веб-службы, а затем другое NSBlockOperation, чтобы выполнить обновление базы данных. Будет зависеть, что операция веб-службы завершается до начала операции обновления базы данных. Вот код, который я пытаюсь выполнить:

__weak DataFetcher *weakSelf = self; 
__block NSArray *serviceQUeryResult; 
NSBlockOperation *webServiceOperation = [NSBlockOperation blockOperationWithBlock:^{ 
    serviceQUeryResult = [weakSelf queryServiceFor:@"mini"]; 
    [weakSelf setData:serviceQUeryResult]; 
}]; 
NSBlockOperation *dbInsertOperation = [NSBlockOperation blockOperationWithBlock:^{ 
    [weakSelf persistData:serviceQUeryResult]; 
}]; 

[webServiceOperation addDependency:dbInsertOperation]; 
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
[queue addOperation:webServiceOperation]; 

При установке этого пути мой queryServiceFor: метод никогда не вызывается. Я также не уверен, где разместить вызовы методов делегата, поскольку они обновляют пользовательский интерфейс и должны находиться в основном потоке. Я использовал GCD несколько раз в прошлом, но теперь вам понадобятся некоторые дополнительные функции NSOperations. Может ли кто-нибудь помочь? Благодаря!

ответ

2

Основная проблема в том, что вы объявили webServiceOperation быть зависимым от dbInsertOperation (т.е. он не запустится, пока webServiceOperationdbInsertOperation отделки), но вы никогда не начать dbInsertOperation, так webServiceOperation никогда не будет запущен.

  1. Если вы хотите сделать dbInsertOperation зависит от webServiceOperation, вы не хотите:

    [webServiceOperation addDependency:dbInsertOperation]; 
    

    Вы вместо этого хотите:

    [dbInsertOperation addDependency:webServiceOperation]; 
    
  2. После того, как вы создали эту зависимость, не забудьте добавить и этих операций в вашу очередь.

    [queue addOperation:webServiceOperation]; 
    [queue addOperation:dbInsertOperation]; 
    

    Зависимость будет гарантировать, что dbInsertOperation не начнется до webServiceOperation отделки. Обратите внимание, это предполагает, что webServiceOperation выполняет свой блок синхронно. Если сетевой запрос выполняется асинхронно, вы можете обернуть его в свой собственный параллельный/асинхронный подкласс NSOperation.


Если вы хотите, чтобы обновить пользовательский интерфейс от этих фоновых операций, вы можете:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
    // update the UI here 
}]; 

или использовать ГКД, если вы хотите:

dispatch_async(dispatch_get_main_queue(), ^{ 
    // update the UI here 
}); 
+0

Спасибо, я неверно предположил, что зависимость неявно добавила другую. Спасибо за прояснение этой части уравнения. – Pheepster

+0

Я все еще не понимаю, куда звонить делегатам. Поскольку они в конечном итоге обновляют пользовательский интерфейс, они не могут быть помещены в очередь, правильно? Итак, с GCD довольно прямолинейно назвать основной поток, но здесь я не уверен, где и как вызывать обновления для пользовательского интерфейса. – Pheepster

+0

Обновления @Pheepster Re UI, вы можете использовать GCD для отправки кода в основную очередь, или вы можете использовать эквивалент очереди операций, который я покажу в своем пересмотренном ответе.Если я нахожусь в операции, я обычно использую исполнение очереди операций, но оба шаблона работают нормально. – Rob

Смежные вопросы