Muhammad Umar
Muhammad Umar

Reputation: 11782

Accessing ViewContext on multiple threads causing crash

I have two UIViewControllers in a Tab Bar

In one of the TabBar I am making an api call using AFNetworking and this api call is saving data in CoreData.

Here is my code

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        for (int i = 0; i < cartList.count; i++)
        {
            NSDictionary *dict = [cartList objectAtIndex:i];
            NSFetchRequest *request = [Orders fetchRequest];
            request.predicate = [NSPredicate predicateWithFormat:@"orderId = %@", [dict objectForKey:kiD]];

            NSError *error = nil;
            NSArray *itemsList = context executeFetchRequest:request error:&error];
            if (itemsList.count == 0)
            {
                Orders *order = [NSEntityDescription insertNewObjectForEntityForName:@"Orders" inManagedObjectContext:appDel.persistentContainer.viewContext];
                [order updateWithDictionary:dict];
                order.isNew = NO;
            }
            else
            {
                Orders *order = [itemsList objectAtIndex:0];
                [order updateWithDictionary:dict];
                order.isNew = NO;
            }
        }

        dispatch_async(dispatch_get_main_queue(), ^{

            [appDel saveContext];
            [self refreshValues:NO];

        });
    });

In second VIewController I am doing something like that. If I switch the tab controllers very fast the app crashes at

 [appDel saveContext];

most probably because the last time viewContext was used by other UIviewController in Background thread.

What is the work around I can adopt to fix this problem

If this is correctly implemented

[appDel.persistentContainer performBackgroundTask:^(NSManagedObjectContext * _Nonnull context)
            {
                NSFetchRequest *request = [Categories fetchRequest];
                NSBatchDeleteRequest *deleteReq = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

                NSError *deleteError = nil;
                [appDel.persistentContainer.viewContext executeRequest:deleteReq error:&deleteError];

                for (int i = 0; i < dataArr.count; i++)
                {
                    Categories *category = [NSEntityDescription insertNewObjectForEntityForName:@"Categories" inManagedObjectContext:appDel.persistentContainer.viewContext];
                    [category updateWithDictionary:[dataArr objectAtIndex:i]];
                }

                @try {

                    NSError *error = nil;
                    [context save:(&error)];
                } @catch (NSException *exception)
                {
                }

                [self getCategoryItems];
            }];

Upvotes: 1

Views: 932

Answers (2)

Jon Rose
Jon Rose

Reputation: 8563

Core-data is not thread-safe, neither for reading for for writing. If you violate this ever core-data can fail in unexpected ways. So even if it appears to work you can find core-data suddenly crashing for no apparent reasons. In other words, accessing core-data from the wrong thread is undefined.

There are a few possible solutions:

1) only use the main thread for reading and writing to core-data. This is an OK solution for simple apps that don't do a lot of data import or export and have relatively small data sets.

2) Wrap NSPersistentContainer's performBackgroundTask in an operation queue and only write to core-data through that method and never write to the viewContext. When you use performBackgroundTask the method gives you a context. You should use the context to fetch any objects that you need, modify them, save the context and then discard the context and the objects.

If you try to write using both performBackgroundTask and writing directly to the viewContext you can get write conflicts and lose data.

Upvotes: 2

Puneet Sharma
Puneet Sharma

Reputation: 9484

Create a child NSManagedObjectContext object with NSPrivateQueueConcurrencyType your data processing in background queue.

Read Concurrency guide for more info.

Upvotes: 0

Related Questions