Reputation: 44886
I have an iOS sync process broken down into a series of asynchronous NSOperation subclasses. These are broken down into those that do heavy processing and those that rely on networking. But most of them also do things with Core Data.
I'm not sure how to perform Core Data operations within the operation.
Here's a couple trivial examples… my real code does several switches in and out of the database context. It also uses @synchronize(self){}
.
NSManagedContext *context = [self newContextFromParent];
__block NSString *someValue;
[context performBlockAndWait:^{
// fetch someValue from Core Data
}];
[self doMoreWorkWithValue:someValue];
[context performBlockAndWait:^{
NSError *e;
if ([context hasChanges]) {
[context saveChanges:&e];
}
}];
This seems on the surface like a good approach, but depending on what I do in performBlockAndWait:
there are potential deadlocks here.
Generally, I like to avoid performBlockAndWait:
in my code and use performBlock:
instead.
[context performBlock:^{
NSString *someValue = @""; // fetch someValue from Core Data
[backgroundQueue addOperationWithBlock:^{
[self doMoreWorkWithValue:someValue withCompletion:^{
[context performBlock:^{
NSError *e;
if ([context hasChanges]) {
[context saveChanges:&e];
}
}];
}];
}];
}];
With this approach, though, I've moved my processing from the thread I was given to whatever thread backgroundQueue
decides to run my process on, and I'm not sure what the better approach is.
If I capture [NSOperation currentQueue]
in the main operation and add to it instead, I've added my block to the end of the queue. What I really want is to resume.
What approach should I be using here?
Upvotes: 1
Views: 93
Reputation: 49054
Your first approach is the one I would use. You mentioned concern about deadlocks inside performBlockAndWait:
, though. Are you concerned about calling into another method that might itself use performBlockAndWait:
? If so, no worries; performBlockAndWait:
is explicitly safe to use re-entrantly. That is: this code is safe (though obviously contrived):
[context performBlockAndWait:^{
[context performBlockAndWait:^{
// fetch someValue from Core Data
}];
}];
If the deadlock concern is not related to Core Data, then it seems like you'd be at just as much of a risk of deadlock inside doMoreWorkWithValue:
, right?
Upvotes: 1