Базовый шаблон Данных: как эффективно обновить локальную информацию с изменениями из сети?

У меня есть некоторая неэффективность в моем приложении, которое я хотел бы понять и зафиксировать.

Мой алгоритм:

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 путем создания запроса предиката с ключом соответствующего объекта, это - часть моей схемы. Я вижу, что и (всегда) и 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 с для запроса прекрасны на устройстве 3G, но если Вы складываете 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 (Базовые Данные int64 свойство на MyObject), как я должен правильно проверить, существует ли соответствующий локальный объект в хранилище CD или нет? Предварительно загрузите полный набор возможных соответствий и затем утвердите локальный массив?

(Одно возможное решение перемещает это в фоновый поток. Это было бы прекрасно, за исключением того, что, когда я получаю изменения от потока и делаю [moc mergeChangesFromContextDidSaveNotification:aNotification]; (измененные объекты от фонового потока посредством уведомления), это тихие блоки.)

5
задан gerry3 5 February 2010 в 17:59
поделиться

5 ответов

Прочтите «Эффективная реализация поиска или создания» в Руководстве по программированию основных данных.

В основном вам нужно создать массив идентификаторов или свойств, таких как имена, или что-то еще, что у вас есть из объекта управляемого объекта.

Затем вам нужно создать предикат, который будет фильтровать управляемые объекты с помощью этого массива.

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

Конечно, «objectIDs» может быть чем угодно, что вы можете использовать для идентификации. Это не обязательно должен быть NSManagedObjectID.

Затем вы можете выполнить один запрос на выборку и перебрать полученные извлеченные объекты, чтобы найти дубликаты. Добавьте новый, если его нет.

9
ответ дан 18 December 2019 в 09:49
поделиться

Вы должны выполнить одну выборку для всех объектов, но только для идентификатора сервера для объектов.

Используйте setPropertiesToFetch: с setResultType: , установленным на NSDictionaryResultType .

3
ответ дан 18 December 2019 в 09:49
поделиться

Я думаю, что ваше предположение о том, что синхронизация совпадает с обновлением HEAD, является ложным. Если в Subclipse parlance «синхронизировать» означает «фиксировать», то это, безусловно, ложь, потому что фиксация не обновляет вашу рабочую копь. вы должны явно обновить после того, как вы обязуетесь быть в HEAD.

Что подводит меня к вашему второму вопросу: я думаю, что причина, по которой жирная линия находится ниже других обязательств, заключается в том, что вышеуказанная причина - обязательство не обновляется. Это означает, что можно зафиксировать изменение файла, а затем просмотреть другой файл и увидеть, что он старше HEAD, поскольку эти другие файлы также не были перенесены в HEAD.

Эта статья может помочь прояснить эту концепцию смешанных редакций: http://markphip.blogspot.com/2006/12/mixed-revision-working-copies.html

Я также призываю вас ознакомиться с документацией SVN , так как работа с плагинами и расширениями для Subversion всегда становится проще, когда вы понимаете, как работает базовая система SVN.

-121--1621881-

Если кто-либо заинтересован, я реализовал это с помощью специального класса «PageRasterizer».

Класс создает QWebPage в конструкторе и устанавливает флаг загрузки bool равным false. Вызов connect () соединяет сигнал loadFinished с слотом элемента, который просто устанавливает флаг загрузки в значение true.

Специальная функция RenderPage () , возвращающая изображение, выполняет всю работу: принимает последовательность HTML и вызывает setHtml () . После этого появляется , пока петля, которая ожидает на флаге; в то время как флаг имеет значение false, вызывается qApp- > processEvents () , так что сигналы излучаются, и в конечном итоге вызывается слот установки флага. Когда это так, цикл разрывается, и теперь вы можете визуализировать страницу в QImage (не забудьте установить флаг обратно в false перед возвращением).

Если вас интересует процесс визуализации, посмотрите на этот пример Qt (функция Миниатюра:: render () ).

Для бонусных точек можно сделать этот класс функтором.

-121--2964720-

Похоже, вам нужен NSSet NSManagedObjectID, который загружается в память или хранится где-то более быстро, чем постоянное хранилище объектов.

Таким образом можно сравнить идентификаторы объектов из сети с идентификаторами объектов из кэша без необходимости выполнения запроса выборки для большого набора данных.

Можно ли добавить идентификатор в кэш из -awakeStartInsert в классы управляемых объектов?

1
ответ дан 18 December 2019 в 09:49
поделиться

Как насчет:

defaultPort = (new Random()).Next(48620, 49150);
-121--981921-

Среда написания сценариев определенно является гражданином второго сорта. То, что вы хотите, называется AlarmManager, используя ELAPSED_REALTIME. Если это недоступно для среды сценариев, вы застряли.

Среда сценариев, по крайней мере в настоящее время, не предназначена для полной замены среды набора разработчика, где можно создавать полные приложения. Она предназначена для того, чтобы позволить вам выполнять некоторые простые скриптовые задачи, за счет того, что быть не способны делать более сложные вещи. Прошу прощения.

-121--2618094-

Вероятно, вы можете извлечь урок из электронной почты клиентов.

Они работают, сначала запрашивая у сервера список идентификаторов сообщений. Как только у клиента есть этот список, он сравнивает его с локальным хранилищем данных, чтобы проверить, отличается ли что-либо от этого.

Если есть разница, нужно одно из пары действий. 1. Если он существует на клиенте, но не на сервере И мы IMAP, то удалить локально. 2. Если он существует на сервере, но не на клиенте, загрузите оставшуюся часть сообщения.

В вашем случае сначала запросите все идентификаторы. Затем отправьте последующий запрос, чтобы получить все данные для тех, которых у вас еще нет.

При наличии ситуации, когда запись может существовать локально, но могла быть обновлена с момента последней загрузки на сервер, запрос должен содержать последнюю обновленную дату.

3
ответ дан 18 December 2019 в 09:49
поделиться

После долгой борьбы с этой же проблемой я, наконец, наткнулся на эту запись в блоге, которая полностью решила ее (и является повторно используемым блоком кода в качестве бонуса!).

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

Пока код образец не покрывает сетевую часть; вам просто нужно загрузить его в NSDictionary. а затем это касается синхронизации локального контекста Core Data.

1
ответ дан 18 December 2019 в 09:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: