Domanda

Ho qualche inefficienza nella mia app che mi piacerebbe capire e correggere.

Il 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

io 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 in su, hai appena ricevuto un bloccante 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. Esso dovrebbe colpire solo il database una volta e dovrebbe venire dalla memoria da allora in poi, giusto? (L'SQL viene eseguito anche per gli oggetti che so per certo esiste localmente e avrebbe dovuto essere caricati nella memoria con le query precedenti.) Ma, se ho solo myObjectId da una fonte esterna, questo è il meglio che ho potuto pensare.

Così, forse la domanda è: se ho myObjectId (una proprietà Int64 Core Data in MyObject), come devo controllare correttamente se l'oggetto locale rilevante esiste in negozio di CD o no? Precaricare l'intero insieme di possibili corrispondenze e poi predicato una matrice locale?

(Una possibile soluzione si sta muovendo ad un thread in background Questo andrebbe bene, solo che quando ricevo le modifiche dal filo e fare [mergeChangesFromContextDidSaveNotification moc: aNotification];. (Cambiarsi oggetti dal thread in background per mezzo di notifica ), questo ancora blocchi.)

È stato utile?

Soluzione

Per saperne di "Implementazione Trova-o-Create efficiente" nella Guida alla programmazione Core Data.

In sostanza è necessario creare una matrice di ID o di immobili come nomi, o qualsiasi cosa avete dall'entità oggetto gestito.

Poi è necessario creare un predicato che filtrerà gli oggetti gestiti utilizzando questa matrice.

[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]];

Naturalmente "objectIds" potrebbe essere qualsiasi cosa che è possibile utilizzare per identificare. Non deve essere il NSManagedObjectID.

Poi si potrebbe fare un FETCH, e iterare gli oggetti recuperati risultanti, per trovare i duplicati. Aggiungere una nuova, se non esiste.

Altri suggerimenti

Si potrebbe probabilmente prendere una lezione da client di posta elettronica.

Funzionano prima interrogando il server per un elenco di ID dei messaggi. Una volta che il cliente ha tale elenco, quindi confronta contro è archivio dati locale per vedere se qualcosa è diverso.

Se c'è una differenza ci vuole uno di un paio di azioni. 1. Se esiste sul client, ma non server e siamo IMAP, quindi eliminare localmente. 2. Se esiste sul server, ma non è cliente, quindi scaricare il resto del messaggio.

Nel tuo caso, prima query per tutti gli ID. Poi invia una query di follow-up per afferrare tutti i dati per quelli che non si dispone già.

Se si dispone di una situazione in cui il record potrebbe esistere a livello locale, ma potrebbe essere stato aggiornato dopo l'ultimo download sul server, quindi la query dovrebbe includere la data dell'ultimo aggiornamento.

Si dovrebbe fare un fetch in tutti gli oggetti, ma prendere solo l'ID del server per gli oggetti.

Usa setPropertiesToFetch: con setResultType:. impostato NSDictionaryResultType

Sembra che quello che vi serve è un NSSet di NSManagedObjectIDs che viene caricato nella memoria o conservato in un luogo più rapidamente accessibili di quanto il tuo negozio oggetto persistente.

In questo modo è possibile confrontare gli ID degli oggetti dalla rete con l'ID oggetto dalla cache senza dover eseguire una richiesta su un grande insieme di dati recupero.

Forse aggiungere l'ID alla cache all'interno -awakeFromInsert all'interno delle classi di entità gestite?

Dopo aver combattuto con questo stesso problema per anni, ho finalmente ci siamo imbattuti in questo blog, che del tutto risolto esso (ed è un blocco di codice riutilizzabile come bonus!).

http://henrik.nyh.se/2007/01/importing-legacy-data-into-core-data-with-the-find-or-create-or-delete-pattern

Mentre il codice di esempio non copre la parte di rete; è sufficiente caricarlo in un NSDictionary. e poi questo si occupa della sincronizzazione del contesto Core Data locale.

Non è una risposta, ma un URL aggiornato la documentazione "Importazione di dati in modo efficiente"

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174-SW1

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top