1

Ich erhalte gelegentlich einen Absturzbericht von Benutzern (den ich nicht selbst reproduzieren kann); Es hat etwas mit NSManagedObjectContext refreshObject zu tun. Die Crash-Meldung istAbsturz mit NSManagedObjectContext refreshObject

„Ein NSManagedObjectContext keine Objekte in anderen Kontexten erfrischen können“

Der Code, wo es abstürzt ist hier:

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; 
} 

Ich bin mir nicht ganz sicher, warum das so ist krachend. Die backgroundContextImage wird erstellt mit NSPrivateQueueConcurrencyType, und ich stelle sicher, dass ich performBlockAndWait beim Abrufen und den Zugriff auf die verwalteten Objekte mit diesem Kontext verwenden. Die filterMainQueue ist eine serielle Warteschlange, um diese Arbeit in einem Hintergrundthread anstelle des Hauptthreads zu unterstützen.

Der Crash-Bericht sieht wie folgt aus:

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 

Irgendwelche Ideen?

+0

Hat Ihre Person Objektverweis andere Objekte Coredata? Deine Instanz einer Person sieht ziemlich sicher aus, aber ist sie irgendwie mit irgendetwas in einem anderen Kontext verbunden? – deanWombourne

+0

Nein, denke nicht ... Es gibt Beziehungen von Person, aber sie sollten in diesem Kontext als Fehler geladen werden. Ich werde mehr zur Bestätigung sehen. Aber ich glaube, dass ein anderer Prozess möglicherweise den persistenten Speicher (und damit den Hauptkontext des verwalteten Objekts) zurücksetzt. Würde das möglicherweise das Problem erklären? –

+0

@ZS ja würde es. – Mundi

Antwort

0

Das Problem war, dass unter bestimmten Umständen etwas anderes in der App den persistentenStore ersetzen und den managedObjectContext zurücksetzen würde, und obwohl die Aufrufe von loadContactReferenceAndImage und refreshObject beide innerhalb von performBlockAndWait liegen. Die Lösung, die ich mit war kam, um zu bestätigen, ob die managedObjectContext die gleiche ist, und erst dann aktualisiert das Objekt:

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

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

     }];