Ich habe etwas Ineffizienz in meiner App, die ich gerne verstehen und beheben würde.Core Data Muster: Wie man lokale Informationen mit Änderungen vom Netz effizient aktualisiert?
Mein Algorithmus ist:
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
ich die Kontrolle auf den Leitungen A und B tue durch ein Prädikat Abfrage mit der entsprechenden Objektschlüssel erstellen, die Teil meines Schema ist. Ich sehe, dass sowohl A (r) und B (wenn die Ausführung in den Teil verzweigt) erzeugen eine SQL wählen wie:
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 für eine Abfrage auf einem 3GS Gerät ist in Ordnung, aber wenn Sie 100 davon hinzufügen Du hast gerade einen 700ms Blocker bekommen.
In meinem Code, ich bin mit einem Helfer diese Fetches zu tun:
- (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
}
Ich finde, dass das falsch ist und ich sollte die Überprüfung auf eine andere Weise tun. Es sollte nur einmal die Datenbank treffen und sollte danach aus dem Speicher kommen, oder? (Das SQL wird auch für Objekte ausgeführt, von denen ich sicher bin, dass sie lokal existieren und mit früheren Abfragen in den Speicher geladen worden sein sollten.) Aber wenn ich myObjectId nur von einer externen Quelle habe, ist dies das Beste, was ich mir vorstellen kann.
Also, die Frage ist vielleicht: Wenn ich myObjectId (eine Core Data Int64-Eigenschaft auf MyObject) habe, wie sollte ich richtig überprüfen, ob das relevante lokale Objekt im CD-Speicher existiert oder nicht? Laden Sie den gesamten Satz möglicher Übereinstimmungen vor und dann ein lokales Array Prädikat?
(Eine mögliche Lösung ist dies zu einem Hintergrund Thread zu verschieben. Das wäre in Ordnung, außer dass, wenn ich die Änderungen aus dem Thread und [Objekte erhalten aus dem Hintergrund thread über Benachrichtigung), blockiert dies immer noch.)
Link? Ich habe den Core Data Programming Guide unter http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html gelesen, aber ich erinnere mich nicht daran, dass Find-or-Create da ist . – Jaanus
Hier ist der Link http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174 –
Ich markierte dieses als die Antwort, weil Es enthält die gleiche Idee wie einige andere (cache-relevante Bezeichner-Eigenschaft), hat aber den zusätzlichen Vorteil der Verknüpfung mit der offiziellen Dokumentation. Find-or-Create ist genau das, worum es geht./Da meine Daten klein sind, habe ich nur das gesamte Objekt in den Speicher geladen, da die Daten klein genug sind und ich irgendwann darauf zugreifen muss, und dieser Cache ist superschnell. – Jaanus