3

I am running into intermittent, hard-to-reproduce errors on my iPhone app, so I am checking my assumptions around concurrency.

Running AFNetworking v0.10.x, I have the following network call:

[self postPath:@"/myEndPoint"
    parameters:params
       success:^(AFHTTPRequestOperation *request, id response)
          {
              AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
              // do stuff with object context here
              [appDelegate.objectContext save];
          }     
]       
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
// do other stuff with object context
[appDelegate.objectContext save];      

In my AppDelegate:

-(NSManagedObjectContext*) objectContext
{
    if(nil == _objectContext)
    {
        ... set up sqlite persistent store coordinator and object model ...

        _objectContext = [[NSManagedObjectContext alloc] init];
        [_objectContext setPersistentStoreCoordinator:persistentStoreCoordinator];
        [_objectContext setMergePolicy:NSOverwriteMergePolicy];
    }
    return _objectContext;
}

Is it possible, in this scenario, to end up with concurrency problems? Or, in other words, is AFNetworking's API thread-safe? I thought the NSOverwriteMergePolicy would cover me for conflicts, but crashing persists (albeit intermittently).

meriial
  • 4,946
  • 2
  • 23
  • 21

2 Answers2

6

AFNetworking's callbacks are executed on the main thread. As a result, they are 'thread-safe', because there is only one thread that is interacting with CoreData. If you only have a single managed object things will be straightforward.

From Apple:

Tasks added to this queue are performed serially on the main thread itself. Therefore, you can use this queue as a synchronization point for work being done in other parts of your application.

There are still lots of considerations when using multi-threaded CoreData and multiple managed object contexts, and for those I refer you to rsswtmr's excellent answer, which doesn't correctly answer my question, but provides links to lots of good information.

Lukas Würzburger
  • 6,543
  • 7
  • 41
  • 75
meriial
  • 4,946
  • 2
  • 23
  • 21
2

You can't have multiple threads working on the same object context. Think through how Core Data might be part-way through changing/committing data while another change comes through on another thread. You need to create a separate context per thread and merge changes when it's safe/appropriate. The NSOverwriteMergePolicy will simply save you from having to manually handle conflicts at merge time.

Look here for a great explanation of threading Core Data access.

rsswtmr
  • 1,776
  • 5
  • 16
  • 26
  • But are AFNetworking's callback blocks not being called on the main thread? From AFHTTPRequestOperation: `dispatch_async(self.successCallbackQueue ?self.successCallbackQueue : dispatch_get_main_queue(), ^{ success(self, self.responseData); });` – meriial Nov 21 '12 at 15:59
  • In any event, main thread or not, you have no guarantee when an asynchronous call is going to drop a change on your code, or even Core Data, while it's working. And when would you save context, after every async call? You're better off accumulating changes into a separate context and merging them on the main thread (synchronized) when you can guarantee atomicity of your data. I've run into this problem several times before and it's maddening because the crashes aren't predictable. Separate contexts seem to solve the issue for me. – rsswtmr Nov 21 '12 at 18:19
  • I think that is the crux of my misunderstanding, and would love a concrete confirmation on: **Even though** AFNetworking's success blocks are executed on the main thread, if I'm going to use Core Data, I MUST treat the ManagedObjectContext in these blocks as if it were in a multi-threaded environment. @rsswtmr, do you have any links that can confirm this? – meriial Nov 21 '12 at 19:46
  • Try [this](http://stackoverflow.com/questions/11428324/coredata-not-compatible-with-an-afnetworking-request-from-a-gcd-queue), and [this](http://stackoverflow.com/questions/11335214/using-core-data-concurrently-and-reliably). At least one person thought the problem was complicated enough to write a library called [AFIncrementalStore](https://github.com/AFNetworking/AFIncrementalStore) specifically for this purpose. – rsswtmr Nov 21 '12 at 22:24
  • 1
    These examples are still based on multi-threaded-ness. I'm continuing to research this, and Apple says this about the main queue: "Tasks added to this queue are performed serially on the main thread itself. Therefore, you can use this queue as a synchronization point for work being done in other parts of your application." So that would indicate that AFNetworking's callbacks are added, serially, to the main queue. – meriial Nov 23 '12 at 05:59