2010-01-26 12 views
55

Estoy tratando de usar datos de núcleo en una forma de hilo múltiple. Simplemente quiero mostrar la aplicación con los datos descargados previamente mientras descargo nuevos datos en segundo plano. Esto debería permitir al usuario acceder a la aplicación durante el proceso de actualización.Aplicación de varios hilos de Data Core

Tengo un NSURLConnection que descarga el archivo asincronously usando delegate (y muestra el progreso), luego uso un XMLParser para analizar los nuevos datos y crear nuevos NSManagedObjects en un contexto separado, con su propio persistentStore y usando un hilo separado .

El problema es que crear nuevos objetos en el mismo contexto que el anterior al mostrarlo puede arrojar una excepción BAD_INSTRUCTION. Entonces, decidí usar un contexto separado para los nuevos datos, pero no puedo encontrar una manera de mover todos los objetos al otro contexto una vez que haya terminado.

Paolo también conocido como SlowTree

Respuesta

138

The Apple Concurrency with Core Data documentation es el lugar para comenzar. Léelo realmente con cuidado ... ¡Fui mordido muchas veces por mis malentendidos!

reglas básicas son:

  1. Utilice uno NSPersistentStoreCoordinator por programa. No los necesitas por hilo.
  2. Crea uno NSManagedObjectContext por cada thread.
  3. Nunca pase un NSManagedObject en un hilo al otro hilo.
  4. En su lugar, obtenga los ID de objeto a través de -objectID y páselo al otro hilo.

Más reglas:

  1. asegúrese de guardar el objeto en la tienda antes de obtener el ID de objeto. Hasta que se guarden, son temporales, y no puedes acceder a ellos desde otro hilo.
  2. Y tenga cuidado con las políticas de fusión si realiza cambios en los objetos gestionados de más de un hilo.
  3. NSManagedObjectContext 's -mergeChangesFromContextDidSaveNotification: es útil.

Pero permítanme repetir, ¡por favor lea el documento con cuidado! ¡Realmente vale la pena!

+1

he encontrado un gran ejemplo de la fusión de contextos en los CoreDataBooks (mergeChangesFromContextDidSaveNotification). Muchas gracias. Que tengas un buen día. Paolo aka SlowTree – SlowTree

+0

Gracias a Dios. Estoy leyendo esto ha resuelto mis problemas. Estaba importando un gran conjunto de datos en una cadena de fondo y obteniendo una multitud de excepciones impredecibles. Instanciar el contexto en el hilo de fondo en lugar de pasarlo parece haber solucionado mis problemas. – tobyc

+2

Este documento aún no se ha actualizado para aprovechar las mejoras muy importantes en iOS 5: el video al que me enlace en mi respuesta es ahora una mejor referencia. – JosephH

2

Espero que esto pueda ayudar a todos los pueblos que encuentran problemas al usar datos básicos en un entorno de múltiples hilos.

Eche un vistazo a "Top Songs 2" en la documentación de Apple. Con este código tomé la "píldora roja" de Matrix, y descubrí un nuevo mundo, sin doble error libre, y sin fallas. : D

Espero que esto ayude.

Paolo

p.s. Muchas gracias a Yuji, en la documentación que describió anteriormente encontré ese ejemplo.

73

Actualmente [mayo de 2015] Apple Concurrency with Core Data documentation es, en el mejor de los casos, muy engañoso, ya que no cubre ninguna de las mejoras en iOS 5 y, por lo tanto, ya no muestra las mejores formas de utilizar datos centrales al mismo tiempo.Hay dos cambios muy importantes en iOS 5: contextos principales y nuevos tipos de concurrencia/subprocesamiento.

No he encontrado ninguna documentación escrita que cubra exhaustivamente estas nuevas características, pero el WWDC 2012 video "Session 214 - Core Data Best Practices" lo explica muy bien.

Magical Record utiliza estas nuevas características y puede valer la pena echarle un vistazo.

Los conceptos básicos reales siguen siendo los mismos: solo puede usar objetos administrados en el subproceso en el que se creó el contexto de objetos administrados.

Ahora puede usar [moc performBlock:] para ejecutar el código en el subproceso derecho.

No hay necesidad de utilizar mergeChangesFromContextDidSaveNotification: más; en su lugar, cree un contexto secundario para realizar los cambios, luego guarde el contexto secundario. Al guardar el contexto secundario, los cambios se incluirán automáticamente en el contexto principal, y para guardar los cambios en el disco solo se realizará un guardado en el contexto principal en su cadena de caracteres.

Para que esto funcione, debe crear el contexto padre con un tipo concurrente, por ejemplo:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

Luego, en el subproceso de fondo:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
[context setParentContext:mainManagedObjectContext]; 

<... perform actions on context ...> 

NSError *error; 
if (![context save:&error]) 
{ 
    <... handle error ...> 
} 
[mainManagedObjectContext performBlock:^{ 
    NSError *e = nil; 
    if (![mainContext save:&e]) 
    { 
     <... handle error ...> 
    } 
}]; 
+0

El enlace WWDC parece estar equivocado, aunque .. – Philip007

+7

Votación a favor de hasta -fecha de información SO debería implementar un mecanismo para promover las respuestas involucradas con el desarrollo de nuevas tecnologías, y restar importancia a las respuestas aceptadas obsoletas. Gracias por recomendar el marco Magic Record. Su documentación se ve muy bien. Probablemente lo intente más tarde. – Philip007

+0

Contrariamente a su fragmento de código, UIManagedDocument crea de forma predeterminada su contexto primario en la cola privada y el contexto secundario en la cola principal. ¿Alguna idea de por qué Apple lo hace? ¿Es totalmente arbitrario? – Philip007