1

I am using GCD to start a long-running background process ('run_loop') that creates an NSManagedObjectContext ('MOC'), monitors CoreData objects, and sometimes (when they're ready) uploads a serialization of them to a webserver and then deletes them.

I am using AFNetworking for the HTTP calls. The problem is in the request completion handler blocks, as the blocks run in a different thread to the owner of the MOC, which isn't supported by CoreData.

I have tried storing the NSThread from the start of the GCD run_loop block, and using performSelector:onThread:run_thread but this just doesn't seem to actually call the selector at all.

I have tried using dispatch_sync(run_queue) but this doesn't guarantee the thread is the same, only the GCD queue. A different MOC save in the main thread later hangs.

Eventually the only thing that worked was to set a boolean in the completion callback handler, and to introduce extra logic to detect the boolean switch and to perform the MOC work from the main run_loop.

Would anyone be able to suggest a more elegant fix? Or is CoreData simply not compatible with an AFNetworking request started from a GCD queue, and I should look at a lower-level thread control from the start?

Dagrada
  • 1,135
  • 12
  • 22

1 Answers1

0

Hmm .. the recommended way to deal with MOC and threads is to always make a new MOC that is a sub-moc of your main thread's MOC. Let the main thread do all the saving, but your GCD threads can basically merge changes to the main MOC.

I've had pretty good success working with https://github.com/magicalpanda/MagicalRecord/ to facilitate this in a simpler fashion.

piotrb
  • 364
  • 1
  • 6
  • Thank you! I now create a second MOC in the completion queue, every time it's called, and I've set up the merge as described in http://stackoverflow.com/questions/6959225/core-data-merge-two-managed-object-context - this works nicely! – Dagrada Jul 11 '12 at 08:58
  • It works, but it still doesn't quite make sense to me; I created the main MOC on a dispatch queue, so using [moc performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification)] doesn't appear to be correct either (surely the mergeChanges.. call should be running on the background thread, not the main thread?) I tried switching it to [moc performSelector:onThread:run_thread, but this doesn't work either, it just hangs. – Dagrada Jul 11 '12 at 16:34
  • GCD is a weird beast, depending on what's needed your block can run pretty much anywhere, synchronous dispatched blocks actually run on the main thread, async ones run on any available thread. You literally have to use a temporary MOC basically everywhere you deal with callbacks or dispatching. – piotrb Jul 26 '12 at 22:33