Tengo un poco de ineficiencia en mi aplicación que me gustaría entender y corregir.Patrón de datos básicos: ¿cómo actualizar eficientemente la información local con los cambios de la red?
Mi algoritmo es:
fetch object collection from network
for each object:
if (corresponding locally stored object not found): -- A
create object
if (a nested related object locally not found): -- B
create a related object
que estoy haciendo la comprobación de las líneas A y B mediante la creación de una consulta predicado con la clave del objeto relevante que es parte de mi esquema. Veo que tanto A (siempre) y B (si la ejecución bifurca en esa parte) generan un SQL seleccionar como:
2010-02-05 01:57:51.092 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE1 t0 WHERE t0.ZID = ?
2010-02-05 01:57:51.097 app[393:207] CoreData: annotation: sql connection fetch time: 0.0046s
2010-02-05 01:57:51.100 app[393:207] CoreData: annotation: total fetch execution time: 0.0074s for 0 rows.
2010-02-05 01:57:51.125 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE2 t0 WHERE t0.ZID = ?
2010-02-05 01:57:51.129 app[393:207] CoreData: annotation: sql connection fetch time: 0.0040s
2010-02-05 01:57:51.132 app[393:207] CoreData: annotation: total fetch execution time: 0.0071s for 0 rows.
0.0071s para una consulta está bien en un dispositivo 3G, pero si se agrega 100 de éstos arriba, acabas de obtener un bloqueador de 700ms.
En mi código, estoy usando un ayudante para hacer estas recuperaciones:
- (MyObject *) myObjectById:(NSNumber *)myObjectId {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[self objectEntity]]; // my entity cache
[fetchRequest setPredicate:[self objectPredicateById:objectId]]; // predicate cache
NSError *error = nil;
NSArray *fetchedObjects = [moc executeFetchRequest:fetchRequest error:&error];
if ([fetchedObjects count] == 1) {
[fetchRequest release];
return [fetchedObjects objectAtIndex:0];
}
[fetchRequest release];
return nil;
}
MyObject *obj = [self myObjectById];
if (!obj) {
// [NSEntityDescription insertNewObjectForEntityForName: ... etc
}
siento que esto está mal y que debería hacer la comprobación de alguna otra manera. Solo debería golpear la base de datos una vez y debería venir de la memoria a partir de entonces, ¿verdad? (El SQL se ejecuta incluso para objetos que sé que existen localmente y deberían haber sido cargados en la memoria con consultas previas). Pero si solo tengo myObjectId de una fuente externa, esto es lo mejor que se me ocurre.
Entonces, quizás la pregunta es: si tengo myObjectId (una propiedad int64 de Core Data en MyObject), ¿cómo debería verificar correctamente si el objeto local relevante existe en la tienda de CD o no? Precargar todo el conjunto de posibles coincidencias y luego predicar una matriz local?
(Una posible solución es mover esto a un hilo de fondo. Esto estaría bien, excepto que cuando obtengo los cambios del hilo y hago [moc mergeChangesFromContextDidSaveNotification: aNotification]; (obteniendo objetos cambiados del hilo del fondo por medio de notificación), esto todavía bloquea.)
Enlace? He leído la Guía de programación de datos básicos en http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html, pero no recuerdo nada de que Find-or-Create esté allí. . – Jaanus
Aquí está el enlace http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174 –
Marqué esta como la respuesta porque lleva la misma idea que varios otros (propiedad de identificador relevante de caché), pero tiene la ventaja adicional de vincular a la documentación oficial. Find-or-Create es exactamente de lo que se trata./En cuanto a mí, dado que mis datos son pequeños, terminé simplemente buscando todo el conjunto de objetos en la memoria, ya que los datos son lo suficientemente pequeños y necesito acceder finalmente, y esta forma de almacenamiento en caché es superrápida. – Jaanus