2
votes

Currently I'm using Restkit to control all my (Core-) data in my app. I'm using it to keep in sync with the server using RKManagedObjectMapping and I use [myMyNSManagedObject createEntitity] together with [[RKObjectManager §sharedManager].objectStore save] to manually edit items within Grand Central Dispatch.

Is there any recommendation to do this in this or an other way? Because sometimes the app freezes in a deadlock executing this code of Restkit

+ (NSArray*)objectsWithFetchRequest:(NSFetchRequest*)fetchRequest {
    NSError* error = nil;
    NSArray* objects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
    if (objects == nil) {
        RKLogError(@"Error: %@", [error localizedDescription]);
    }
    return objects;
}

with that

- (NSError*)save {
    NSManagedObjectContext* moc = [self managedObjectContext];
    NSError *error;
    @try {
        if (![moc save:&error]) {
            if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToSaveContext:error:exception:)]) {
…

in parallel. Before I switched to Restkit I put a "context performBlockAndWait" around each entity-editing code and was on the safe side with no deadlocks. I have no other NSManagedObjectContext or something created by myself, all comes from Restkit.

2
I believe I'm encountering a similar problem. Did you ever get anywhere with this? - elsurudo
I tried to get rid of all gcd calls together with RestKit Object Mapping. Now it works. - netshark1000
What do you mean by that? You got rid of all RestKit object mapping on the background thread? Then what do you do about your main thread's UI performance? - elsurudo
Call objectmapping from the main thread. restkit will do the threading. - netshark1000
Unfortunately in my case, that's not possible - elsurudo

2 Answers

0
votes

In my case, the problem was that I was passing NSManagedObjects across thread boundaries, and using them on threads other than the ones on which they were fetched from their respective NSManagedObjectContext. It was really subtle in my case, as I knew that I wasn't supposed to do this, but did it accidentally anyways. Instead of passing the managed objects, I started passing the NSManagedObjectIDs (and then fetching from the local thread's MOC), and haven't encountered a deadlock since. I'd recommend you do a deep scan of your code to make sure you are only using managed objects in the threads that spawned them.

0
votes

We've encountered this exact problem in our app. Basically, CoreData nested contexts are very buggy in iOS5, and thus don't work as advertised. This has many manifestations, but one of them is the problem described above, deadlocking a fetch request vs. a background operation. This is well documented, instructive quote:

NSFetchedResultsController deadlocks

You never want your application to deadlock. With NSFetchedResultsController and nested contexts, it’s pretty easy to do. Using the same UIManagedDocument setup described above, executing fetch requests in the private queue context while using NSFetchedResultsController with the main queue context will likely deadlock. If you start both at about the same time it happens with almost 100% consistency. NSFetchedResultsController is probably acquiring a lock that it shouldn’t be. This has been reported as fixed for an upcoming release of iOS.

This SO answer has a possible fix that keeps nested contexts. I've seen others like it, basically liberally applying -performAndWait: calls. We haven't tried that yet (iOS5 has single digit percentages in our user base). Otherwise, the only other "fix" we know right now is abandoning nested contexts for iOS5 (cf. this SO answer).

That CoreData continues to be fundamentally broken for multithreading (in iOS 5) is inexcusable on Apple's part. You can make a good case now that trusting Apple on CoreData (multithreading, iCloud) seems to be opening a bag of pain.