Search code examples
iosobjective-ccore-datansmanagedobjectcontextnsfetchrequest

iOS Core Data fetch in background causing crashing


In my app I am constantly doing Core Data work in the background.

Testflight has been reporting a lot of crashes on a specific fetch which gets the current logged in environment object from Core Data (I cannot replicate):

- (Environment *)getActiveEnvironment
{
    AppDelegate *ad = [AppDelegate sharedAppDelegate];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    [context setParentContext:ad.managedObjectContext];
    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Environment" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    
    NSError *error;

    //crash points to this line
    NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
    
    Environment *tempE = nil;
    if(items.count > 0)
    {
        for(Environment *e in items)
        {
            if(!e.token && !e.url)
            {
                break;
            }
            
            Environment *mainContextTv = (Environment *)[ad.managedObjectContext objectWithID:e.objectID];
            if(e.activeValue)
                 tempE = mainContextTv;                
        }  
    }

    return tempE;
}

Here is the crash stack I am receiving from Testflight:

0   Tower-iSales-Tab    0x002b37b2  testflight_backtrace
1   Tower-iSales-Tab    0x002b2e4a  TFSignalHandler
2   libsystem_platform.dylib    0x39144722  _sigtramp
3   CoreData    0x2e1b8cec  _perform
4   CoreData    0x2e1c30f4  -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
5   CoreData    0x2e13477a  -[NSManagedObjectContext executeFetchRequest:error:]
6   Tower-iSales-Tab    0x000c7082  -[MySingleton getActiveEnvironment] in MySingleton.m on Line 379
7   Tower-iSales-Tab    0x000c73f8  -[MySingleton getToken] in MySingleton.m on Line 416
8   Tower-iSales-Tab    0x0020c476  -[NetworkManager getPathForViewName:useTimeStamp:timeStamp:index:counter:] in NetworkManager.m on Line 699
9   Tower-iSales-Tab    0x0020aa5a  __70-[NetworkManager checkForDataFilesShouldEmptyQueue:isInitialDownload:]_block_invoke167 in NetworkManager.m on Line 415
10  libdispatch.dylib   0x3901b8fa  _dispatch_barrier_sync_f_invoke
11  Tower-iSales-Tab    0x0020a33e  __70-[NetworkManager checkForDataFilesShouldEmptyQueue:isInitialDownload:]_block_invoke113 in NetworkManager.m on Line 335
12  libdispatch.dylib   0x39017102  _dispatch_call_block_and_release
13  libdispatch.dylib   0x3901c7e4  _dispatch_root_queue_drain
14  libdispatch.dylib   0x3901c9d0  _dispatch_worker_thread2
15  libsystem_pthread.dylib 0x39146dfe  _pthread_wqthread
16  libsystem_pthread.dylib 0x39146cc3  start_wqthread

I read this answer which suggests to set the queue type to NSPrivateQueueConcurrencyType, not NSConfinementConcurrencyType which I can do, but this is not a crash I can replicate easily so i'd like to know for sure that would cause this crash.

That answer also suggest using the performBlockAndWait block for background fetches, but in my function how would I? I need to return an Environment object, I use this function all over my app.

Thanks


Solution

  • From what I understand, you don't have to use NSConfinementConcurrencyType context here, as you're calling -getActiveEnvironment only from the main thread. So you can do all operations on the main context (ad.managedObjectContext).

    The returned object should then be accessed only from the main thread. If you want to access it from some other thread you have to use objectWithID: to get it in the context associated with that thread.