В моем приложении есть неэффективность, которую я хотел бы понять и исправить.
Мой алгоритм:
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
Я выполняю проверку строк A и B, создавая запрос предиката с ключом соответствующего объекта, который является частью моей схемы. Я вижу, что и A (всегда), и B (если выполнение разветвляется на эту часть) генерируют SQL-запрос, например:
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,0071 с для запроса - это нормально на устройстве 3GS, но если вы добавите 100 из них, вы просто получите блокиратор 700 мс.
В моем коде я использую помощника для выполнения этих выборок:
- (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
}
Я чувствую, что это неправильно, и я должен сделать проверку другим способом. Он должен попадать в базу данных только один раз и впоследствии должен быть из памяти, верно? (SQL выполняется даже для тех объектов, которые, я знаю, существуют локально и должны были быть загружены в память с помощью предыдущих запросов.) Но, если у меня есть только myObjectId из внешнего источника, это лучшее, что я мог придумать.
Итак, возможно, вопрос заключается в следующем: если у меня есть myObjectId (свойство Core Data int64 в MyObject), как мне правильно проверить, существует ли соответствующий локальный объект в хранилище компакт-дисков или нет? Предварительно загрузить весь набор возможных совпадений, а затем предсказать локальный массив?
(Одно из возможных решений - переместить это в фоновый поток. Это было бы хорошо, за исключением того, что когда я получаю изменения из потока и выполняю [moc mergeChangesFromContextDidSaveNotification: aNotification]; (получение измененных объектов из фонового потока посредством уведомления ), это все еще блокирует.)