objective-c ios core-data nsmanagedobject nsmanagedobjectcontext

objective c - CoreData no pudo cumplir una falla por



objective-c ios (5)

Tengo un problema realmente molesto, que parece que no me solucionan.

Tengo una vista cuando envío un mensaje que se guarda en los datos centrales, cuando lo hizo solicitó a la base de datos un mensaje aleatorio (frase) y también lo guardó en otra fila de la base de datos.

Si hago la última parte codificada, sin obtener datos de la base de datos, funciona todo muy bien, pero tan pronto como obtengo la fila aleatoria de la base de datos, se vuelve loco.

En mi AppDelegate.m:

- (void)save { NSAssert(self.context != nil, @"Not initialized"); NSError *error = nil; BOOL failed = [self.context hasChanges] && ![self.context save:&error]; NSAssert1(!failed,@"Save failed %@",[error userInfo]); } - (NSString*)selectRandomSentence { NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentences" inManagedObjectContext:self.managedObjectContext]; [request setEntity:entity]; NSError *error = nil; NSUInteger count = [self.context countForFetchRequest:request error:&error]; NSUInteger offset = count - (arc4random() % count); [request setFetchOffset:offset]; [request setFetchLimit:1]; NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error]; [request release]; return [[sentenceArray objectAtIndex:0] sentence]; } - (NSManagedObjectContext *)context { if (_managedObjectContext != nil) return _managedObjectContext; NSPersistentStoreCoordinator *coordinator = [self coordinator]; if (coordinator != nil) { _managedObjectContext = [[NSManagedObjectContext alloc] init]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return _managedObjectContext; }

En mi ChatController.m:

- (void)didRecieveMessage:(NSString *)message { [self addMessage:message fromMe:NO]; } #pragma mark - #pragma mark SendControllerDelegate - (void)didSendMessage:(NSString*)text { [self addMessage:text fromMe:YES]; } #pragma mark - #pragma mark Private methods - (void)responseReceived:(NSString*)response { [self addMessage:response fromMe:NO]; } - (void)addMessage:(NSString*)text fromMe:(BOOL)fromMe { NSAssert(self.repository != nil, @"Not initialized"); Message *msg = [self.repository messageForBuddy:self.buddy]; msg.text = text; msg.fromMe = fromMe; if (fromMe) { [self.bot talkWithBot:text]; } [self.repository asyncSave]; [self.tableView reloadData]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:[self.buddy.messages count] - 1] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }

En My OfflineBot.m:

- (void)talkWithBot:(NSString *)textFromMe { AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; [self didRecieveMessage:[delegate selectRandomSentence]]; } - (void)didRecieveMessage:(NSString *)message { if ([self.delegate respondsToSelector:@selector(didRecieveMessage:)]) [self.delegate didRecieveMessage:message]; }

Repository.m

- (Message*)messageForBuddy:(Buddy*)buddy { Message *msg = [self.delegate entityForName:@"Message"]; msg.source = buddy; [self.delegate.managedObjectContext refreshObject:buddy mergeChanges:YES]; return msg; } - (void)asyncSave { [self.delegate save]; }

El error:

2012-08-10 00: 28: 20.526 Chat [13170: c07] * Error de aserción en - [AppDelegate guardar], /Users/paulp/Desktop/TestTask/Classes/AppDelegate.m:28 2012-08-10 00:28 : 20.527 Chat [13170: c07] * Aplicación de finalización debido a excepción no detectada ''NSInternalInconsistencyException'', razón: ''Error de guardado {type = inmutable dict, count = 2, entries => 1: {contents = "NSAffectedObjectsErrorKey"} = ("( entity: Sentences; id: 0x6b8bf10; data:) ") 2: {contents =" NSUnderlyingException "} = CoreData no pudo cumplir una falla para ''0x6b8bf10''}

¿Qué estoy haciendo mal?

Actualización : identifiqué el error en esta fila:

NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

Cuando ejecuto esa fila, obtengo el error ... que es cuando obtengo los datos. El error, sin embargo, parece aparecer al guardar los datos nuevos en la entidad Mensajes. La oración aleatoria se obtiene de Sentences.

Después de cambiar el método asyncSave para guardarlo directamente (sin usar un nuevo hilo) guarda el primer chat, pero nada después de eso. Se muere.

Actualizar Todo parece funcionar usando esto en mi didFinishLaunchingWithOptions :

[self.context setRetainsRegisteredObjects:YES];

Entiendo que, por este medio, el Contexto del Modelo de Objetos CodeData no libera sus objetos, que parece ser el problema entre los que se agregan y guardan. ¿Pero por qué?


Esto sucede porque está agregando el "mensaje aleatorio" a su nueva fila antes de completar la búsqueda de todas las relaciones de la primera llamada.

Puede agregar una captación previa a su primera llamada para evitar la carga lenta y el problema se resolverá, creo.

Así es como podemos hacer la captación previa para la solicitud:

[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@"whatEverOfYourWillNumberOne",@"whatEverOfYourWillNumberTwo", nil]];

Espero que ayude.


Hmm. ¿Está implementando apropiadamente concurrencia siguiendo esta guía ? El problema que está viendo es común cuando se usan datos centrales en varios subprocesos. El objeto fue eliminado en su "contexto de fondo", mientras que otro contexto lo está accediendo. Llamar a [context processPendingChanges] en el contexto de fondo después de la eliminación pero antes de guardar puede ser útil.

También hay una sesión de WWDC 2010 (137) sobre la optimización del rendimiento de los datos centrales que se elimina un poco.

Cuando ejecuta una búsqueda, Core Data devuelve una colección de objetos que coinciden con el predicado que proporcionó. Esos objetos en realidad no tienen sus valores de propiedad establecidos todavía. Cuando accedes a una propiedad, Core Data regresa a la tienda para "disparar el error": rellena la propiedad con datos de la tienda. "No se pudo cumplir un error ..." las excepciones se producen cuando Core Data va a la tienda para obtener los valores de las propiedades de un objeto, pero el objeto no existe en el almacén persistente. El contexto del objeto gestionado pensó que debería existir, por lo que podría intentar la falla, que es donde está el problema. El contexto que provocó que se lanzara la excepción no sabía que este objeto había sido eliminado de la tienda por otra cosa (como otro contexto).

Tenga en cuenta que la Guía de simultaneidad anterior está desactualizada, debe usar contextos de elementos primarios y secundarios y concurrencia de colas privadas en lugar del antiguo modelo de confinamiento de subprocesos. Los contextos de elementos primarios y secundarios tienen muchas menos probabilidades de encontrarse con "No se pudo cumplir una falla ..." por muchas razones. Y, por favor, presente un error de documentación o use el formulario de comentarios para solicitar que se actualice la guía de simultaneidad.


Realmente no es conceptualmente posible " guardar " objetos de Datos Básicos " en filas diferentes ". Recuerde, Core Data es un gráfico de objetos y no una base de datos.

Si quiere "reubicar" su oración, la mejor manera es destruirla y volver a crearla. Si desea conservar la instancia anterior, simplemente cree una nueva y luego complete las propiedades de la existente.

Para destruir, usa

[self.context deleteObject:sentenceObject];

Para recrear, use

Sentence *newSentence = [NSEntityDescription insertNewObjectForEntityForName: "Sentences" inManagedObjectContext:self.context]; newSentence.sentence = sentenceObject.sentence; // fill in other properties, then [self.context save:error];

Si desea leer sobre esto, consulte " Copiar y copiar y pegar " en la sección "Uso de objetos administrados" de la "Guía de programación de datos básicos".


Solucioné el error cambiando la cadena "cacheName" de NSFetchedResultsController a nil.

NSFetchedResultsController * aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest managedObjectContext: self.managedObjectContext sectionNameKeyPath: nil cacheName: @ "Root" nil ];


verifica el mecanismo de datos básicos. "Las fallas reducen la cantidad de memoria que consume su aplicación. Un error es un objeto de marcador de posición que representa un objeto gestionado que aún no se ha realizado del todo, o un objeto de recopilación que representa una relación:"