Core Data no guarda objects de manera persistente

Soy nuevo en Core Data y, como tal, no estoy seguro si estoy cometiendo un error. He descargado algunos datos de una API REST y guarda con éxito la respuesta JSON en el disco. Estoy tratando de procesar los datos y savelos de manera persistente usando Core Data.

 NSLog(@"inserted objects: %@", [managedObjectContext insertedObjects]); [managedObjectContext performBlockAndWait:^{ NSError *error = nil; if (![managedObjectContext save:&error]) { NSLog(@"Unable to save context for class %@", className); } else { NSLog(@"saved all records!"); } }]; 

He procesado correctamente el JSON y lo agregué a un NSManagedObjectContext . En la primera línea, muestra que he intentado correctamente insert 2 objects.

 inserted objects: {( <User: 0xa259af0> (entity: User; id: 0xa259b70 <x-conetworkingata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F3> ; data: { email = "vishnu@vishnuprem.com"; experience = "2013-07-20"; "first_name" = Vishnu; id = 2; "job_title" = Developer; "last_name" = Prem; location = ""; "phone_number" = "+6590091516"; "profile_pic" = ""; "thumbnail_profile_pic" = ""; "user_id" = 2; }), <User: 0xa25e460> (entity: User; id: 0xa25e4c0 <x-conetworkingata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F2> ; data: { email = "sanchitbareja@gmail.com"; experience = "2013-07-20"; "first_name" = Sanchit; id = 1; "job_title" = Developer; "last_name" = Bareja; location = ""; "phone_number" = "+15106127328"; "profile_pic" = ""; "thumbnail_profile_pic" = ""; "user_id" = 1; }) )} 

Cuando intenté [managedObjectContext save:&error] , lo hace con éxito e imprime "guardado todos los loggings" como se esperaba. Sin embargo, cuando voy a mi file .sqlite aplicación y .sqlite los objects agregados, me doy count de que no ha agregado ningún object a la database.

En el relanzamiento de la aplicación, imprimo una list de objects que ya están en la database y confirma que aún no he guardado ninguno.

¿Alguien sabe lo que está sucediendo y por qué no soy capaz de save los datos de forma persistente a pesar de que parece que he creado con éxito los objects 'Usuario' que deben savese en el model Core Data.

EDITAR:

aquí es donde creo el NSPersistentStoreCoordinator

 // Returns the persistent store coordinator for the application. // If the coordinator doesn't already exist, it is created and the application's store added to it. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (_persistentStoreCoordinator != nil) { return _persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"RTModel.sqlite"]; NSError *error = nil; NSLog(@"Test 1"); _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; NSLog(@"Test 2"); if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { /* Replace this implementation with code to handle the error appropriately. abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. Typical reasons for an error here include: * The persistent store is not accessible; * The schema for the persistent store is incompatible with current managed object model. Check the error message to determine what the actual problem was. If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. If you encounter schema incompatibility errors during development, you can networkinguce their frequency by: * Simply deleting the existing store: [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] * Performing automatic lightweight migration by passing the following dictionary as the options parameter: [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _persistentStoreCoordinator; } 

Tengo 3 contexts

  • masterManagedObjectContext

  • backgroundManagedObjectContext

  • newManagedObjectContext

master es padre de background y nuevo. Cuando busco en contexts como este:

  NSError *error = nil; NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"User"]; [request setSortDescriptors:[NSArray arrayWithObject: [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES]]]; [request setReturnsObjectsAsFaults:NO]; NSArray *testArray = [[[RTCoreDataController shanetworkingInstance] newManagedObjectContext] executeFetchRequest:request error:&error]; for (User *obj in testArray) { NSLog(@"obj.id %@", obj.id); } NSLog(@"query records: %@",testArray); 

maestro y background, ambos devuelven el obj.id correcto en el NSLog y también dan la salida a continuación para @ "loggings de consulta"

  ( "<User: 0xa3811d0> (entity: User; id: 0xa381230 <x-conetworkingata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A002> ; data: {\n email = \"sanchitbareja@gmail.com\";\n experience = \"2013-07-20\";\n \"first_name\" = Sanchit;\n id = 1;\n \"job_title\" = Developer;\n \"last_name\" = Bareja;\n location = \"\";\n \"phone_number\" = \"+15106127328\";\n \"profile_pic\" = \"\";\n \"thumbnail_profile_pic\" = \"\";\n \"user_id\" = 1;\n})", "<User: 0xa382170> (entity: User; id: 0xa3820b0 <x-conetworkingata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A003> ; data: {\n email = \"vishnu@vishnuprem.com\";\n experience = \"2013-07-20\";\n \"first_name\" = Vishnu;\n id = 2;\n \"job_title\" = Developer;\n \"last_name\" = Prem;\n location = \"\";\n \"phone_number\" = \"+6590091516\";\n \"profile_pic\" = \"\";\n \"thumbnail_profile_pic\" = \"\";\n \"user_id\" = 2;\n})" ) 

sin embargo, "nuevo" devuelve (null) para el obj.id en NSLog y devuelve lo siguiente para @"query records" :

 ( "<User: 0xa2b08a0> (entity: User; id: 0x95aebe0 <x-conetworkingata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A762> ; data: <fault>)", "<User: 0xa2b0910> (entity: User; id: 0xa4b9780 <x-conetworkingata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A763> ; data: <fault>)" ) 

Desde su código y los comentarios, parece que no está guardando el context maestro. Asegúrate de llamar

 [managedObjectContext save:&error]; 

en todos los contexts secundarios que guardan los datos, y luego también en el context maestro.

Acabo de golpearme la cabeza contra esencialmente el mismo problema. Un UITableViewController obtuvo una subclass de NSManagedObject de NSManagedObjectContext, comprobó si un atributo era nulo, y si se downloadon los datos, estableció ese atributo y luego guardó el NSManagedObjectContext. Algo como esto:

 MyManagedObject *mgObject = //get object from NSFetchResultsController NSManagedObjectContext *mgObContext = mgObject.managedObjectContext; if (!mgObject.data) { mgObject.data = [NSData dataWithContentsOfURL:urlWithData]; [mgObContext performBlock ^{ NSError *saveError = nil; BOOL saveResult = [mgObContext save:&saveError]; if (saveError || !saveResult) { NSLog(@"Save not successful.."); } }]; } //do something with myObject.data 

La function save daba un retorno boolean SÍ y saveError permanecía nulo, pero si salía de la aplicación y volvía a iniciarse, cuando mis Datos Núcleo cargan mis subclasss NSManagedObject, el atributo de datos era nulo, y cuando este UITableViewController volvía a upload, tenía para download los datos nuevamente.

No pude encontrar una solución para esto en ninguna parte … leer la documentation de Core Data no ayudó. La solución vino a mí cuando consideré la diferencia entre el código anterior y mi código que establece los attributes en los methods de fábrica de la subclass NSManagedObject, que es básicamente:

 MyManagedObject *mgObject = [NSEntityForDescription insertNewObjectForEntityName:@"MyManagedObject" inManagedContext:mgObContext]; mgObject.attribute1 = some value mgObject.attribute2 = another value 

La única diferencia es que estoy llamando a los methods de fábrica desde el interior de [mgObContext performBlock:].

Entonces, el código enmendado es:

 MyManagedObject *mgObject = //get object from NSFetchResultsController NSManagedObjectContext *mgObContext = mgObject.managedObjectContext; if (!mgObject.data) { [mgObContext performBlock: ^{ mgObject.data = [NSData dataWithContentsOfURL:urlWithData]; NSError *saveError = nil; BOOL saveResult = [mgObContext save:&saveError]; if (saveError || !saveResult) { NSLog(@"Save not successful.."); } }]; } //do something with myObject.data 

Que, hasta ahora, está funcionando a la perfección. Entonces, creo que cada vez que realiza modificaciones en los attributes de NSManagedObjects, debe hacerlo en el hilo de su NSManagedObjectContext.

Pensé que también añadiría algo de información a las personas que pueden tener problemas similares.

En mi experiencia, el bash de save objects que no tienen suficientes campos completados no parece persistir cuando se guardan, y no parece que se produzcan errores cuando este es el caso. Siempre verifique que sus campos se rellenen como se esperaba antes de save los incendios.

Otra forma de ver estos types de problemas es voltear el problema en la cabeza. Tal vez el object sí guardó, pero el método en el que está verificando que se han guardado de hecho es incorrecto. A menudo, puede hacer esto consultando CoreData para el logging (s) usando ciertos criterios. Comtesting que tus criterios son correctos y que tu consulta realmente está devolviendo lo que esperas.

Si no devuelve lo que espera, podría deberse a sus propios errores, pero también podría ser que la matriz que almacena los resultados no los almacene correctamente. Me he topado con casos en los que tuve que renombrar un NSArray porque algo sobre el nombre de la matriz estaba causando problemas de reference y, por lo tanto, la matriz no podía apuntar a los resultados que esperaba. Aclamaciones.

Soy un principiante con iOS, pero he hecho un ejemplo con CoreData para almacenar información de usuarios.

Primero, necesitas crear tu model con tu entidad (supongo que ya lo has hecho). En mi ejemplo, mi entidad se llama "Usuario".

Primero, agregue una propiedad similar a esta

 NSManagedObjectContext *context; 

a su class ViewController.

Segundo, en su método viewDidLoad, agregue estas dos líneas:

 AppDelegate *appdelegate = [[UIApplication shanetworkingApplication]delegate]; context = [appdelegate managedObjectContext]; 

Y tercero, almacene su información:

 NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context]; NSManagedObject *newUser = [[NSManagedObject alloc]initWithEntity:entitydesc insertIntoManagedObjectContext:context]; [newUser setValue:(NSString *)[dictionary objectForKey:@"name"] forKey:@"name"]; [newUser setValue:(NSString *)[dictionary objectForKey:@"surname"] forKey:@"surname"]; ... NSError *error; [context save:&error]; 

(Tomo mis properties de un dictionary NSDictionary llamado)

Para leer su información:

 AppDelegate *appdelegate = [[UIApplication shanetworkingApplication]delegate]; context = [appdelegate managedObjectContext]; NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context]; NSFetchRequest *request = [[NSFetchRequest alloc]init]; [request setEntity:entitydesc]; //NSPnetworkingicate *pnetworkingicate = [NSPnetworkingicate pnetworkingicateWithFormat:@"NULL"]; [request setPnetworkingicate:nil]; NSError *error; NSArray *matchingData = [context executeFetchRequest:request error:&error]; //NSArray *matchingData = [context executeFetchRequest:nil error:&error]; // If the user is not logged in previously if (matchingData.count <=0 ){ //self.displaylabel.text = @"No person find"; } else { // If the user is already logged in for (NSManagedObject *obj in matchingData) { AppDataModel *appDataModel=[AppDataModel getInstance]; appDataModel.appUserInfo = [User alloc]; appDataModel.appUserInfo.name = [obj valueForKey:@"name"]; appDataModel.appUserInfo.surname = [obj valueForKey:@"surname"]; } } 

Sé que esta no es una respuesta a lo que pidió el OP, pero quería compartir mi experiencia sobre el mismo tema en caso de que ayude a otra persona.

Tuve algunos problemas con el almacenamiento de datos de forma persistente, todo parecía ayudarme a solucionarlo. La estructura era muy simple, una entidad con un campo y una relación (to-many). Hice algunos cambios en la class generada, NSMutableOrdenetworkingSet lugar de NSOrdenetworkingSet .

No estaba haciendo multi thread, ni nada por el estilo, simplemente agregando elementos a la relación. Después de save y volver a iniciar la aplicación, los datos simplemente desaparecieron (elementos agregados a la relación).

Terminé descubriendo que hay una propiedad llamada actualizada . Después de agregar el nuevo elemento a la relación, comprobé si esta propiedad cambió su valor. No lo hizo Así que tuve que crear otro campo en la Entidad, un Booleano, solo para poder forzar que la entidad se savea después de agregar elementos a esta relación.

 entity.addObject(..) entity.forceUpdate = true // without this line, it won't update managedContext.save(..) 

Así que espero que ayude a cualquier persona con el mismo problema, ya que pasé algún time pensando que no lo estaba guardando correctamente ..

Agregue esto después de save sus datos:

 NSError *error = nil; if (![managedObjectContext save:&error]) { NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]); } 

Después de horas de debugging, descubrí que la razón por la que mis actualizaciones no se guardaban era porque en mi subclass de NSManagedObject I definía las properties w / @synthesize lugar de @dynamic .

Después de cambiarlo, todo se guardó como se esperaba.

Espero que haya ayudado a alguien.