NSSortDescriptor de NSFetchRequest no funciona después de save el context

Estoy haciendo operaciones en una queue de despacho de GCD en un NSManagedObjectContext definido así:

- (NSManagedObjectContext *)backgroundContext { if (backgroundContext == nil) { self.backgroundContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread]; } return backgroundContext; } 

MR_contextThatNotifiesDefaultContextOnMainThread es un método de MagicalRecord :

 NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [context setParentContext:[NSManagedObjectContext MR_defaultContext]]; return context; 

Después de search mis objects y darles la position de queue correcta, los logging y el pedido es correcto. Sin embargo, el segundo logging parece ser completamente aleatorio, el descriptor de sorting claramente no funciona.

He networkingucido el problema a [self.backgroundContext save:&error] . Después de save el context de background, los descriptores de sorting están rotos.

 dispatch_group_async(backgroundGroup, backgroundQueue, ^{ // ... for (FooObject *obj in fetchedObjects) { // ... obj.queuePosition = [NSNumber numberWithInteger:newQueuePosition++]; } NSFetchRequest *f = [NSFetchRequest fetchRequestWithEntityName:[FooObject entityName]]; f.pnetworkingicate = [NSPnetworkingicate pnetworkingicateWithFormat:@"queuePosition > 0"]; f.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"queuePosition" ascending:YES]]; NSArray *queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil]; for (FooObject *obj in queuedObjects) { DLog(@"%@ %@", obj.queuePosition, obj.title); } if ([self.backgroundContext hasChanges]) { DLog(@"Changes"); NSError *error = nil; if ([self.backgroundContext save:&error] == NO) { DLog(@"Error: %@", error); } } queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil]; for (FooObject *obj in queuedObjects) { DLog(@"%@ %@", obj.queuePosition, obj.title); } }); 

No tengo idea de por qué el descriptor de sorting no está funcionando, ¿los expertos de Core Data quieren ayudar?

Actualizar:

El problema no ocurre en iOS 4. Creo que la razón está en la diferencia entre el aislamiento de subprocesss y los modos de queue privada. MagicalRecord utiliza automáticamente el nuevo patrón de concurrency que parece comportarse de manera diferente.

Actualización 2:

El problema se ha resuelto agregando un guardado del context de background:

 if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) { DLog(@"Changes"); NSError *error = nil; if ([[NSManagedObjectContext MR_contextForCurrentThread] save:&error] == NO) { DLog(@"Error: %@", error); } else { NSManagedObjectContext *parent = [NSManagedObjectContext MR_contextForCurrentThread].parentContext; [parent performBlockAndWait:^{ NSError *error = nil; if ([parent save:&error] == NO) { DLog(@"Error saving parent context: %@", error); } }]; } } 

Actualización 3:

MagicalRecord ofrece un método para save recursivamente un context, ahora mi código se ve así:

 if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) { DLog(@"Changes"); [[NSManagedObjectContext MR_contextForCurrentThread] MR_saveWithErrorHandler:^(NSError *error) { DLog(@"Error saving context: %@", error); }]; } 

Me avergüenzo de no haberlo usado en primer lugar …

Sin embargo, no sé por qué esto ayuda y me gustaría get una explicación.

Trataré de comentar, ya que escribí MagicalRecord.

Por lo tanto, en iOS5, MagicalRecord está configurado para intentar utilizar el nuevo método Private Queue de múltiples contexts de objects gestionados. Esto significa que un guardado en el context secundario solo empuja guarda al padre. Solo cuando un padre sin más padres salva, el guardado permanece en su tienda. Esto es probablemente lo que estaba sucediendo en su versión de MagicalRecord.

MagicalRecord ha tratado de manejar esto para usted en las versiones posteriores. Es decir, intentaría elegir entre el modo de queue privada y el modo de aislamiento de subprocesss. Como descubrió, eso no funciona muy bien. La única forma verdaderamente compatible de escribir código (sin reglas complejas de preprocesador, etc.) para iOS4 e iOS5 es usar el modo clásico de aislamiento de subprocesss. MagicalRecord de la label 1.8.3 lo admite y debería funcionar para ambos. Desde el 2.0, solo serán las queues privadas de aquí en adelante.

Y, si observa el método MR_save, verá que también está realizando la comprobación de hasChanges (que también puede ser innecesario ya que los componentes internos de Core Data también pueden manejarlo). De todos modos, less código debería tener para escribir y mantener …

La razón subyacente real por la que su configuration original no funcionó es un error de Apple cuando se obtiene de un context secundario con descriptores de sorting cuando el context padre aún no se ha guardado para almacenar:

NSSortdescriptor ineficaz en el resultado de búsqueda de NSManagedContext

Si hay alguna manera de evitar los contexts nesteds, evítelos, ya que todavía son extremadamente complicados y es probable que se sientan decepcionados con las supuestas ganancias de performance, cf. también: http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

Como CoreData no es un marco de subprocesss seguros y para cada subprocess (queue de operaciones), los datos centrales utilizan contexts de diferencias. Consulte la siguiente excelente escritura

http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/