2013-10-04 4 views
8

Ho aggiornato la mia app per supportare iOS 7 e hanno dovuto affrontare il problema che su uno degli schermi nella mia [context save]; ricevo il seguente errore:NSMergeConflict su iOS7

NSCocoaErrorDomain Code=133020 "The operation couldn’t be completed. (Cocoa error 133020.)" UserInfo=0x1115a6d0 {conflictList=(
"NSMergeConflict (0x1115a670) for NSManagedObject (0xf25c850) with objectID '0xf25c070 <x-coredata://76AF57C8-F7FF-4880-B06B-63F8B780C96D/Screen/p7>' with oldVersion = 5 and newVersion = 6 
and old object snapshot = {\n index = 3;\n message = \"<null>\";\n status = 0;\n} and new cached row = {\n index = 3;\n message = \"<null>\";\n status = 0;\n}" 

Su iOS6 questo problema non si verifica .

Update: Codice per managedObjectContext

-(NSManagedObjectContext *)managedObjectContextForCurrentThread{ 
if ([NSThread isMainThread]) 
{ 
    NSManagedObjectContext *parentContext = self.mainManagedObjectContext.parentContext; 
    [parentContext performBlockAndWait:^{ 
     NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]; 
     [[self mainManagedObjectContext] setMergePolicy:mergePolicy]; 
    }]; 
    return self.mainManagedObjectContext; 
} 
else 
{ 
    NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; 
    NSManagedObjectContext *threadContext = [threadDict objectForKey:kCGMManagedObjectContextKey]; 
    if (threadContext == nil) 
    { 
     threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     NSManagedObjectContext *parentContext = self.mainManagedObjectContext.parentContext; 
     [parentContext performBlockAndWait:^{ 
      NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]; 
      [parentContext setMergePolicy:mergePolicy]; 
     }]; 
     [threadContext setParentContext:self.mainManagedObjectContext]; 
     [threadDict setObject:threadContext forKey:kCGMManagedObjectContextKey]; 
    } 
    return threadContext; 
} 

}

+0

Esattamente lo stesso problema che sto affrontando, qualsiasi soluzione che hai trovato? Non riesco a capire perché ci sia questo problema, iOS 6 non si lamenta. Nel mio caso non vedo alcuna ragione per cui questo dovrebbe accadere in quanto il ManagedObject che sto modificando è dallo stesso ManagedObjectContext che sto salvando, perché dovrebbe lamentarsi degli errori di fusione? –

risposta

15

Secondo la documentazione di Apple

NSManagedObjectMergeError = 133020

questo codice di errore per indicare che una politica unione è fallita-Core Data non è in grado di completare la fusione.

C'è qualche criterio di unione nel codice? Si prega di provare NSMergeByPropertyObjectTrumpMergePolicy.

16

Ho appena trascorso due giorni eseguendo il debug dello stesso errore. La differenza tra la tua app e la mia è che la mia accede solo ai dati principali dal thread principale, quindi l'errore di fusione è stato ancora più sconcertante.

Nel nostro caso l'ho ristretto al fatto che avevamo una relazione unidirezionale - A ha molti Bs (modellato come un NSSet), ma B non ne conosce la A. Abbiamo avuto un metodo che modifica sia un e una B, e causerebbe un errore di fusione quando siamo andati a salvare quelle modifiche. Questo codice ha funzionato a lungo su iOS 5 & 6 e ha iniziato a fallire solo su iOS 7.

È vero che l'aggiunta di un criterio di unione farà scomparire l'errore, ma potrebbe anche mascherare altri errori. Nel nostro caso preferiremmo vedere quegli errori piuttosto che rischiare di avere un DB incoerente.

La modifica della relazione in bidirezionale ha comportato l'errore. I collegamenti posteriori non sono necessari per la nostra app, ma non fanno male neanche loro. (E felicemente, la modifica di questa relazione è stata gestita correttamente come migrazione leggera: i dati principali sono stati automaticamente inseriti in questi collegamenti posteriori.)

+0

Ho avuto lo stesso identico problema e questo mi ha aiutato a risolverlo! NSMergeConflict non era molto chiaro:/ – davbryn

+0

Ricorda inoltre di impostare il campo "Inverse" nell'editor di Core Data. Avevamo relazioni bidirezionali nell'app ma lo sviluppatore si è dimenticato di installare Inverse correttamente e questo ha causato questo pseudo conflitto. –

0

Ho ricevuto un errore simile e nel mio caso, il blocco di NSPersistentStoreCoordinator ha funzionato.

[context.persistentStoreCoordinator lock]; 
[context performBlockAndWait:^{ 
    // do something 
}]; 
[context.persistentStoreCoordinator unlock] 

Non so perché funzioni, ma sospetto il bug di NSManagedObjectContext. Spero che questo possa essere d'aiuto.

0

Ho ottenuto questo quando si esegue il test con una memoria completa. Quindi sembra che qualsiasi tipo di errore di fusione (nel mio caso, la memoria è piena e l'archivio persistente non può essere aggiornato) genererà questo.

5

Utilizzando Xcode 6.3.2 con estensione Apple Watchkit e ho ottenuto lo stesso errore quando si tenta di effettuare più aggiornamenti e salva. Il setMergePolicy risolto il problema e qui sono il codice swift:

context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy 

Assicurarsi di mettere la riga sopra prima del comando context.save.

+0

Utilizzando Swift, questo ha funzionato perfettamente nel risolvere essenzialmente lo stesso problema. Grazie! – Pierce

+0

Avrei ** mai ** trovato questo! Non voglio nemmeno sapere quante ore di lettura e risoluzione dei problemi questa singola linea mi ha appena salvato. –

1

Non volevo mascherare un potenziale problema impostando un criterio di unione senza capire prima cosa causasse lo NSMergeConflict.

Nella mia situazione avevo già eseguito uno NSBatchDeleteRequest nel mio codice. Lo NSBatchDeleteRequest viene eseguito direttamente sul coordinatore dell'archivio permanente, pertanto lo ManagedObjectContext non era al corrente delle eliminazioni e conservava ancora i riferimenti agli oggetti eliminati. Quando in seguito ho fatto riferimento a uno di questi oggetti e ho provato a salvare il contesto, è stato lanciato lo NSMergeConflict.

La chiamata reset() sul mio moc dopo aver eseguito la cancellazione ha risolto il problema.

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Tasks") 
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) 
try managedContext.execute(batchDeleteRequest) 
managedContext.reset()