2010-07-19 11 views
7

Sto sviluppando un'app per iPhone con Core Data. Tutti i dati dell'utente devono essere sincronizzati con i nostri server. A tale scopo ho creato una sottoclasse di NSOperation che carica nuovi dati dal nostro servizio web e crea oggetti gestiti corrispondenti. Per mantenere le relazioni tra di loro, ogni oggetto viene trasmesso con un remoteID (che è la chiave primaria del DB del server relazionale).Core Data executeFetchRequest genera NSGenericException (la raccolta è stata modificata mentre veniva enumerata)

Diciamo che ci sono due oggetti gestiti: Dipartimento < - >> Dipendente. La sincronizzazione funziona come segue:

  1. carico tutti i reparti da server. Per ogni dipartimento: crea un oggetto Department e imposta il suo remoteID.

  2. Carica tutti i dipendenti dal server. Per ogni dipendente: creare oggetto Dipendente, recuperare il Dipartimento correlato (da remoteID) e assegnarlo al dipendente.

Recupero di un reparto porta alla seguente eccezione:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x69c8a10> was mutated while being enumerated.<CFBasicHash 0x69c8a10 [0x2d6d380]>{type = mutable set, count = 1424, 
entries => <A list of all newly created entities> 

*** Call stack at first throw: 
0 CoreFoundation 0x02d04919 __exceptionPreprocess + 185 
1 libobjc.A.dylib 0x02e525de objc_exception_throw + 47 
2 CoreFoundation 0x02d043d9 __NSFastEnumerationMutationHandler + 377 
3 CoreData  0x026225d0 -[NSManagedObjectContext executeFetchRequest:error:] + 4400 
4 myApp   0x00059de4 +[AppFactory departmentWithRemoteID:inManagedObjectContext:] + 259 

L'eccezione non viene generata ogni volta. Lo spostamento del codice sul thread principale risolve il problema. Non ho idea di cosa c'è che non va. Ho creato un nuovo NSManagedObjectContaxt nel thread di sincronizzazione e passato tutti gli oggetti gestiti dal suo NSManagedObjectID.

Qualche idea?

risposta

1

Fuori dalla parte superiore della mia testa: il thread "sincronizzazione" aggiunge nuovi oggetti alla raccolta Department durante l'iterazione sul thread principale?

In genere, questo tipo di eccezione si verifica quando si modifica una raccolta nello stesso momento in cui viene enumerata. In uno scenario multi-thread, potrebbe anche significare che la tua raccolta viene enumerata e aggiornata contemporaneamente senza una corretta sincronizzazione dei thread.

+0

per me questa potrebbe essere la ragione per questo tipo di problema. Qual è il modo migliore per risolvere questi problemi, hai qualche idea di @octy? –

+0

Adeem, una buona risposta alla tua domanda è stata fornita in una discussione collegata: http://stackoverflow.com/questions/3364769/iphone-nsfetchedresultscontroller-with-delegate-and-data-update-from-a-separate – octy

4

L'errore "someCollection è stato mutato mentre viene enumerato" è causato dalla modifica di una raccolta mutabile, ad esempio array, dizionario, set ecc., Mentre un enumeratore lo sta attraversando. Poiché non è possibile enumerare un target in movimento, viene generato un errore.

In questo caso, è probabile che l'errore sia causato tentando di enumerare la relazione dei dipendenti del dipartimento sul thread principale, ad es. per la visualizzazione in una vista tabella, mentre il thread in background aggiunge contemporaneamente dipendenti alla relazione.

Ha funzionato, è necessario bloccare l'interfaccia utente mentre si uniscono le modifiche dal thread in background. Per le visualizzazioni delle tabelle, un controller dei risultati recuperato (NSFetchedResultsController) con metodi delegati correttamente implementati nel controller tableview gestirà il problema in modo corretto.

L'importante è inviare beginUpdates a tableview prima di unire i nuovi dati. Questo dirà alla tabella che la struttura dei dati sottostante è stata modificata, quindi non tenterà di ridisegnare se stessa. Una volta completata l'unione, inviare endUpdates a tableview per farlo visualizzare le nuove informazioni.

+0

Ho pensato su questo tipo di problemi e quindi ho creato due NSManagedObjectContexts (uno per il thread principale e uno per il thread di sincronizzazione). Non è una soluzione valida? Uso anche NSFetchedResultsController per le mie visualizzazioni di tabelle. – Roland

+0

Sì, ma quando si uniscono le modifiche apportate dai contesti, si attiva la necessità di aggiornare per riflettere le modifiche apportate nell'altro. I metodi dei delegati FRC consentono di bloccare l'interfaccia utente mentre tali modifiche vengono elaborate. Quindi sblocchi l'interfaccia utente e lascia che mostri gli aggiornamenti. Questo processo è solitamente invisibile all'utente. – TechZen

+0

L'app si arresta in modo anomalo prima di unire le modifiche nel thread principale. – Roland

13

Ho avuto lo stesso problema ... E 'stato risolto perché stavo usando il managedObjectContext che è stato creato sul thread principale su un thread in background. La soluzione era di creare un diverso ManagedObjectContext sul thread in background e utilizzare il persistentStoreCoordinator regolare ... ha funzionato bene dopo quello!

0

Ho avuto lo stesso problema. È possibile utilizzare il blocco, sbloccare il ricevitore. Ho risolto questo problema fino ad ora.

Problemi correlati