1

Я получаю случайный отчет о сбоях от пользователей (который я не могу воспроизвести самостоятельно); это как-то связано с NSManagedObjectContext refreshObject. Сообщение крахCrash with NSManagedObjectContext refreshObject

«NSManagedObjectContext не может обновить объекты в других контекстах»

код, где он выходит из строя здесь:

dispatch_async(self.filterMainQueue, ^{ 
    NSArray *items = [Person getAllNonPrivatePersonsWithContext: self.backgroundContextImage]; 

    if (items.count) { 

     for (Person *person in items) { 

       [self.backgroundContextImage performBlockAndWait: ^{ 
        [person loadContactReferenceAndImage]; 

        // crashes here 
        [self.backgroundContextImage refreshObject: person mergeChanges:NO]; 
       }]; 
     }    
    } 
}); 

+ (NSArray *) getAllNonPrivatePersonsWithContext: (NSManagedObjectContext *) context{ 

    __block NSArray *items = nil; 

    [context performBlockAndWait: ^{ 
     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
     // Edit the entity name as appropriate. 
     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext: context]; 
     [fetchRequest setEntity:entity]; 
     // Set the batch size to a suitable number. 
     //[fetchRequest setFetchBatchSize: 500]; 
     [fetchRequest setPredicate: [NSPredicate predicateWithFormat: @"isContactPrivate == FALSE"]]; 
     [fetchRequest setReturnsObjectsAsFaults: FALSE]; 
     [fetchRequest setIncludesPendingChanges: FALSE]; 

     NSError *error = nil; 
     items = [context executeFetchRequest:fetchRequest error:&error]; 

    }]; 
    return items; 
} 

Я не совсем уверен, почему это сбой. backgroundContextImage создается с использованием NSPrivateQueueConcurrencyType, и я убеждаюсь, что использую performBlockAndWait при извлечении и доступе к управляемым объектам с этим контекстом. filterMainQueue является последовательной очередью, чтобы помочь выполнить эту работу в фоновом потоке вместо основного потока.

Отчет аварии выглядит следующим образом:

Exception Type: SIGABRT 
Exception Codes: #0 at 0x197fb7140 
Crashed Thread: 3 

Application Specific Information: 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObjectContext cannot refresh objects in other contexts.' 

Last Exception Backtrace: 
0 CoreFoundation      0x0000000182a98f48 __exceptionPreprocess + 124 
1 libobjc.A.dylib      0x000000019764bf80 objc_exception_throw + 52 
2 CoreData        0x0000000182786898 -[NSManagedObjectContext refreshObject:mergeChanges:] + 1320 
3 CJournal        0x00000001001729c4 __75-[ContactsSyncController loadContactImagesAndLinksWithPermissionWithBlock:]_block_invoke_2 (ContactsSyncController.m:102) 
4 CoreData        0x00000001827dc900 developerSubmittedBlockToNSManagedObjectContextPerform + 192 
5 libdispatch.dylib     0x0000000197e696a8 _dispatch_client_callout + 12 
6 libdispatch.dylib     0x0000000197e74954 _dispatch_barrier_sync_f_invoke + 96 
7 CoreData        0x00000001827dc7e8 -[NSManagedObjectContext performBlockAndWait:] + 248 
8 CJournal        0x00000001001728bc __75-[ContactsSyncController loadContactImagesAndLinksWithPermissionWithBlock:]_block_invoke (ContactsSyncController.m:97) 
9 libdispatch.dylib     0x0000000197e696e8 _dispatch_call_block_and_release + 20 
10 libdispatch.dylib     0x0000000197e696a8 _dispatch_client_callout + 12 
11 libdispatch.dylib     0x0000000197e756ec _dispatch_queue_drain + 860 
12 libdispatch.dylib     0x0000000197e6d1ac _dispatch_queue_invoke + 460 
13 libdispatch.dylib     0x0000000197e696a8 _dispatch_client_callout + 12 
14 libdispatch.dylib     0x0000000197e77b40 _dispatch_root_queue_drain + 2136 
15 libdispatch.dylib     0x0000000197e772dc _dispatch_worker_thread3 + 108 
16 libsystem_pthread.dylib    0x000000019807d470 _pthread_wqthread + 1088 
17 libsystem_pthread.dylib    0x000000019807d020 start_wqthread + 0 

Любые идеи?

+0

ли в вашей ссылки лицо объекта любые другие объекты CoreData? Ваш экземпляр человека выглядит довольно безопасно, но каким-то образом он привязан к чему-либо в другом контексте? – deanWombourne

+0

Нет, не думаю, что так ... есть отношения от Лица, но они должны загружаться как недостатки в этом контексте. Я буду больше смотреть на подтверждение. Но моя догадка заключается в том, что другой процесс потенциально перезапускает постоянное хранилище (и вместе с ним - основной контекст управляемого объекта). Может ли это объяснить проблему? –

+0

@ZS да, будет. – Mundi

ответ

0

Проблема заключалась в том, что в особых случаях что-то еще в приложении заменит persistentStore и сбросит managedObjectContext, и даже несмотря на то, что вызовы loadContactReferenceAndImage и refreshObject находятся как внутри executeBlockAndWait. Решение, которое я придумал было подтвердить, если managedObjectContext было то же самое, и только затем обновить объект:

 [self.backgroundContextImage performBlockAndWait: ^{ 
       [person loadContactReferenceAndImage]; 

       // MOC could have been updated by another thread 
       if (person.managedObjectContext == self.backgroundContextImage) { 
        [self.backgroundContextImage refreshObject: person mergeChanges:NO]; 
       } 

     }];