2012-08-16 14 views
27

Tengo una aplicación con dos lograron configuración de contextos de objetos como esto:Datos principales: ¿Los contextos secundarios alguna vez obtienen ID de objeto permanentes para objetos recién insertados?

  • Contexto Padres: NSPrivateQueueConcurrencyType, vinculado al almacén persistente.
  • Contexto principal: NSMainQueueConcurrencyType, hijo del contexto principal.

Al insertar un nuevo objeto logrado el contexto principal, ahorro el marco principal y luego el contexto de los padres de esta manera:

[context performBlockAndWait:^{ 
    NSError * error = nil; 
    if (![context save: &error]) { 
     NSLog(@"Core Data save error %@, %@", error, [error userInfo]); 
    } 
}]; 

[parentContext performBlock:^{ 
    NSError *error = nil; 
    BOOL result = [parentContext save: &error]; 
    if (! result) { 
     NSLog(@"Core Data save error in parent context %@, %@", error, [error userInfo]); 
    } 
}]; 

Mi entendimiento es que cuando el objeto gestionar se crea por primera vez, se tiene un objectID temporal. Luego se guarda el contexto principal y este objeto, con su ID temporal, llega al contexto principal. Entonces el contexto principal se guarda. Cuando se guarda este último contexto, el objectID temporal en el contexto principal se transforma en un objectID permanente.

Así:

  • ¿Tiene el objeto de identificación permanente vez tienes propagan automáticamente a el contexto principal (niño)?
  • Cuando fuerzo para obtener el objeto permanente de identificación con [NSManagedObjectContext obtainPermanentIDsForObjects:error:], entonces fondo de la aplicación, reactivarlo, recargar, obtener el objeto utilizando contextual principal de objectWithID:, y acceso a una propiedad, consigo

    "CoreData podía no cumple una falla por ... ".

¿Qué hay de malo en este enfoque?

+0

Jorge: Estoy recibiendo un CoreData no pudo cumplir un error al obtener una identificación permanente en un contexto secundario y guardar el ManagedObject. ¿Descubriste cuál fue el motivo? Gracias –

Respuesta

40

Se trata de un error conocido, es de esperar solucionará en breve, pero en general, la obtención de una identificación permanente es suficiente, siempre que lo haga antes de guardar los datos en el primer hijo, y que incluyen sólo los objetos insertados:

[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:&error] 

En algunos casos complejos, es mejor obtener una identificación permanente tan pronto como crea la instancia, especialmente si tiene relaciones complejas.

¿Cómo y cuándo llamas al obtainPermanentIDsForObjects?

No sigo la parte sobre la falla de la aplicación. Tal vez una mejor explicación sería de ayuda.

+0

No hay nada en el conjunto moc.insertedObjects. Supongo que eso se borrará después del salvamento. Lo que estoy haciendo es guardar la selección de documentos del usuario cuando la aplicación está en segundo plano. La aplicación puede actualizar esos mientras está en segundo plano. Cuando entra en primer plano, el contexto se recrea y la selección se restaura utilizando las ID de objeto. Sin embargo, antes de pasar al segundo plano, los documentos recién creados tienen identificadores temporales incluso después de guardar el contexto. Si fuerzo a obtener los ID permanentes para esos, cuando la aplicación se reactiva, no puede volver a crear los objetos administrados. – Jorge

+1

Sí, insertObjects solo contiene objetos que se han insertado y no guardado. Incluso después de darles identificaciones permanentes, permanecerán en insertObjects hasta que se guarden. Intente hacer la obtención en el contexto de su hijo antes de guardar. Debe capturar los ID, luego propagar el guardado basado en ellos. Asegúrese de guardar completamente en todos los contextos de la base de datos. –

+0

La obtención de los ID justo antes de guardar hizo el truco. ¡Gracias! – Jorge

8

Como dijo Jody anterior, al crear un nuevo NSManagedObject en un subproceso en segundo plano usando un niño ManagedObjectContext debe forzar la creación de una identificación permanente haciendo lo siguiente antes de guardar:

NSError *error = nil; 

[threadedMOC obtainPermanentIDsForObjects:threadedMOC.insertedObjects.allObjects error:&error]; 

BOOL success = [threadedMOC save:&error]; 

en mi humilde opinión, no es realmente intuitivo para hacerlo de esta manera; después de todo, ¡está pidiendo una ID permanente ANTES de que ahorre! Pero esta es la forma en que parece funcionar. Si solicita la identificación permanente después de guardar, entonces la identificación seguirá siendo temporal.En la Apple Docs, en realidad se puede utilizar lo siguiente para determinar si el ID del objeto es temporal:

BOOL isTemporary = [[managedObject objectID] isTemporaryID]; 
1

problema todavía existe en iOS 8.3 Solución en Swift:

func saveContext(context: NSManagedObjectContext?){ 
    NSOperationQueue.mainQueue().addOperationWithBlock(){ 
    if let moc = context { 
     var error : NSError? = nil 
     if !moc.obtainPermanentIDsForObjects(Array(moc.insertedObjects), error: &error){ 
      println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)") 
     } 
     if moc.hasChanges && !moc.save(&error){ 
      println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)") 
     } 
    } 
} 
} 

func saveBackgroundContext(){ 
    saveContext(self.defaultContext) 

    privateContext?.performBlock{ 
     var error : NSError? = nil 
     if let context = self.privateContext { 

      if context.hasChanges && !context.save(&error){ 
       println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)") 
      }else { 
       println("saved private context to disk") 
      } 
     } 
    } 
} 

Dónde:

  • defaultContext tiene concurrencyType .MainQueueConcurrencyType
  • privateContext tiene concurrencyType .PrivateQueueConcurrencyType
Cuestiones relacionadas