Многопоточное приложение Core Data
Я пытаюсь использовать основные данные несколькими способами.
Я просто хочу показать приложение с ранее загруженными данными во время загрузки новых данных в фоновом режиме.
Это должно позволить пользователю получить доступ к приложению в процессе обновления.
У меня есть NSURLConnection, который загружает файл асинхронно с помощью делегата (и показывает прогресс), затем я использую XMLParser для анализа новых данных и создания новых NSManagedObjects в отдельном контексте со своим собственным persistentStore и использованием отдельного потока.
Проблема состоит в том, что при создании новых объектов в том же контексте старого при его показе может быть выбрано исключение BAD_INSTRUCTION.
Итак, я решил использовать отдельный контекст для новых данных, но я не могу понять способ перемещения всех объектов в другой контекст после завершения.
Паоло aka SlowTree
Ответы
Ответ 1
Яблоко Concurrency с документацией по основным данным - это место для начала. Прочтите это очень внимательно... Меня много раз укусили мои недоразумения!
Основные правила:
- Используйте один
NSPersistentStoreCoordinator
для каждой программы. Вы не нуждаетесь в них в потоке.
- Создайте один
NSManagedObjectContext
для каждого потока.
- Никогда не пропускайте
NSManagedObject
в потоке в другой поток.
- Вместо этого получите идентификаторы объектов через
-objectID
и передайте их в другой поток.
Дополнительные правила:
- Перед тем, как получить идентификатор объекта, сохраните объект в хранилище. Пока они не сохранены, они временны, и вы не можете получить к ним доступ из другого потока.
- И будьте осторожны с политиками слияния, если вы вносите изменения в управляемые объекты из более чем одного потока.
-
NSManagedObjectContext
-mergeChangesFromContextDidSaveNotification:
.
Но позвольте мне повторить, пожалуйста, внимательно прочитайте документ! Это действительно того стоит!
Ответ 2
В настоящее время [май 2015 г.] Apple Concurrency с документацией по основным данным в лучшем случае очень вводит в заблуждение, так как не охватывает какие-либо улучшения в iOS 5 и, следовательно, больше не показывает наилучшие способы одновременного использования данных ядра. В iOS 5 есть два очень важных изменения: родительский контекст и новые типы concurrency/threading.
Я еще не нашел письменной документации, которая всесторонне охватывает эти новые функции, но WWDC 2012 видео "Сессия 214 - Основные рекомендации по лучшим данным" объясняет все это очень хорошо.
Magical Record использует эти новые функции и может стоить взгляда.
Реальные основы все те же: вы все же можете использовать только управляемые объекты, в которые был создан поток, управляемый им контекстом объекта.
Теперь вы можете использовать [moc performBlock:] для запуска кода в нужном потоке.
Нет необходимости использовать mergeChangesFromContextDidSaveNotification: больше; вместо этого создайте дочерний контекст для внесения изменений, а затем сохраните дочерний контекст. Сохранение дочернего контекста автоматически введет изменения в родительский контекст, а для сохранения изменений на диске просто выполните сохранение в родительском контексте в нем.
Для этого вы должны создать родительский контекст с параллельным типом, например:
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
Затем в фоновом потоке:
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[context setParentContext:mainManagedObjectContext];
<... perform actions on context ...>
NSError *error;
if (![context save:&error])
{
<... handle error ...>
}
[mainManagedObjectContext performBlock:^{
NSError *e = nil;
if (![mainContext save:&e])
{
<... handle error ...>
}
}];
Ответ 3
Я надеюсь, что это поможет всем народам, которые сталкиваются с проблемами, используя основные данные в многопоточной среде.
Взгляните на "Лучшие песни 2" в документации на яблоко. С помощью этого кода я взял "красную таблетку" Matrix и обнаружил новый мир без двойной ошибки и без ошибок.: D
Надеюсь, что это поможет.
Паоло
p.s.
Огромное спасибо Юджи, в документации, описанной выше, я нашел этот пример.