cdub
cdub

Reputation: 25701

App crashes when saving in different thread

I have a method which creates a separate thread:

// Create thread
dispatch_queue_t uniqueQueue = dispatch_queue_create("Unique Email Queue", NULL);

// Run block on another thread called downloadQueue
dispatch_async(uniqueQueue, ^{

     // Save to core data for redundancy
        User *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.managedObjectContext];

        coreDataUser.username = [emailStr lowercaseString];
        coreDataUser.email = emailStr;
        coreDataUser.name = nameStr;

        NSError *error;

        if (![self.managedObjectContext save:&error])
        {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }            
    }

The app always crashes on this line:

User *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.managedObjectContext];

I am using this tutorial as a reference: http://www.codigator.com/tutorials/ios-core-data-tutorial-with-example/

What am I missing?

Upvotes: 1

Views: 1060

Answers (2)

AntonijoDev
AntonijoDev

Reputation: 1315

NSManagedObjectContext is not threadsafe, try to create new moc in side of the async block. Try:

// Create thread
dispatch_queue_t uniqueQueue = dispatch_queue_create("Unique Email Queue", NULL);

// Run block on another thread called downloadQueue
dispatch_async(uniqueQueue, ^{

     // Save to core data for redundancy
        NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:persistentStoreCoordinator];

        User *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:context];

        coreDataUser.username = [emailStr lowercaseString];
        coreDataUser.email = emailStr;
        coreDataUser.name = nameStr;

        NSError *error;

        if (![context save:&error])
        {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }            
    }

The persistent store is in your AppDelegate

Upvotes: 4

Jakub
Jakub

Reputation: 13860

Remember - CoraData is not thread safe !!!!!

If you want separate thread for your managedObjectContext you have to create one on this thread. To call proper context you have to run it with performBlock block. In your case:

[self.managedObjectContext performBlock:^{
        User *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.managedObjectContext];

        coreDataUser.username = [emailStr lowercaseString];
        coreDataUser.email = emailStr;
        coreDataUser.name = nameStr;

        NSError *error;

        if (![self.managedObjectContext save:&error])
        {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }   
}];

But remember, if you creating context on mainThread, your block is also executed on mainThread.

Upvotes: 3

Related Questions