Ho alcune inefficienze nella mia app che mi piacerebbe capire e risolvere.Schema dei dati principali: come aggiornare in modo efficiente le informazioni locali con le modifiche dalla rete?
mio algoritmo è:
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
sto facendo il controllo sulle linee A e B con la creazione di una query predicato con la chiave del relativo oggetto che fa parte del mio schema. Vedo che sia A (sempre) e B (se l'esecuzione ramificata in quella parte) generano uno SQL SELECT come:
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 per una query va bene su un dispositivo 3G, ma se si aggiungono 100 di questi su, hai appena un blocco da 700ms.
Nel mio codice, sto usando un aiutante di fare queste recupera:
- (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
}
sento che questo è sbagliato e avrei dovuto fare il check in qualche altro modo. Dovrebbe solo colpire il database una volta e dovrebbe venire dalla memoria in seguito, giusto? (L'SQL viene eseguito anche per oggetti che so di sicuro esistono localmente e dovrebbero essere stati caricati in memoria con query precedenti.) Ma, se ho solo myObjectId da una fonte esterna, questo è il meglio che potrei pensare.
Quindi, forse la domanda è: se ho myObjectId (una proprietà int64 di Core Data su MyObject), come dovrei controllare correttamente se l'oggetto locale pertinente esiste nell'archivio CD o no? Precaricare l'intera serie di possibili corrispondenze e quindi predicare un array locale?
(Una possibile soluzione è lo spostamento di un thread in background.Questo sarebbe corretto, tranne che quando ottengo le modifiche dal thread e faccio [moc mergeChangesFromContextDidSaveNotification: aNotification]; (ottenere gli oggetti modificati dal thread in background per mezzo di notifica), questo blocca ancora.)
Link? Ho letto la Guida alla programmazione dei dati di base su http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html, ma non ricordo nulla di Find-or-Create lì . – Jaanus
Ecco il link http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174 –
Ho contrassegnato questo come risposta perché porta la stessa idea di molti altri (proprietà identificatore della cache rilevante), ma ha il vantaggio aggiuntivo di collegarsi alla documentazione ufficiale. Find-or-Create è esattamente ciò di cui si tratta./Per quanto mi riguarda, dato che i miei dati sono piccoli, ho finito con il recupero dell'intero oggetto impostato in memoria, dal momento che i dati sono abbastanza piccoli e ho bisogno di accedervi, e questa modalità cache è super veloce. – Jaanus