I have a model class called DataFetcher that fetches data via a web service, then persists the data to a Core Data datastore, then updates a ViewController via delegate methods. Here is the normal sequence (which works properly) without using NSOperation:
NSArray *serviceQueryResult = [self queryServiceFor:@"car"];
[self setData:serviceQueryResult];
[self persistData:_data];
[_loadDelegate updateCount:_data.count];
[_loadDelegate receivedData:_data];
I need to place the web service call and the database update call on a background thread. My thoughts are to create an NSBlockOperation to make the web service call, then another NSBlockOperation to do the database update. There will be a dependency that the web service operation completes before the database update operation begins. Here is the code I am trying to implement:
__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];
When set up this way my queryServiceFor: method never gets called. I am also unsure of where to place the two delegate method calls since they update the UI and should be on the main thread. I have used GCD several times in the past, but now will be needing some of the extra functionality of NSOperations. Can anyone help? Thanks!
The fundamental issue is that you've declared
webServiceOperationto be dependent upondbInsertOperation(i.e. it won't startwebServiceOperationuntildbInsertOperationfinishes), but you never startdbInsertOperation, sowebServiceOperationwill never run.If you want to make
dbInsertOperationdependent uponwebServiceOperation, you don't want:You instead want:
Once you've created this dependency, make sure to add both of these operations to your queue.
The dependency will ensure that
dbInsertOperationwon't start untilwebServiceOperationfinishes. Note, this assumes thatwebServiceOperationperforms its block synchronously. If the network request runs asynchronously, you might want to wrap it in its own concurrent/asynchronousNSOperationsubclass.If you want to update the UI from these background operations, you can either:
or use GCD, if you want: