2010-01-26 6 views
55

Я пытаюсь использовать основные данные в многопоточном режиме. Я просто хочу показать приложение с ранее загруженными данными во время загрузки новых данных в фоновом режиме. Это должно позволить пользователю получить доступ к приложению во время процесса обновления.Многопоточное приложение Core Data

У меня есть NSURLConnection, который загружает файл асинхронно с помощью делегата (и показывая ход), затем я использую XMLParser для анализа новых данных и создания новых NSManagedObjects в отдельном контексте с собственным постоянным хранилищем и использованием отдельного потока ,

Проблема в том, что при создании новых объектов в том же контексте старого при его показе может быть выбрано исключение BAD_INSTRUCTION. Итак, я решил использовать отдельный контекст для новых данных, но не могу найти способ переместить все объекты в другой контекст после завершения.

Paolo ака SlowTree

ответ

138

The Apple Concurrency with Core Data documentation это место, чтобы начать. Прочтите это очень внимательно ... Меня много раз укусили мои недоразумения!

Основные правила:

  1. Используйте один NSPersistentStoreCoordinator в программе. Вы не нуждаетесь в них в каждой теме.
  2. Создайте один NSManagedObjectContext в каждой теме.
  3. Никогда не пропустите NSManagedObject на нитке в другую резьбу.
  4. Вместо этого получите идентификаторы объектов через -objectID и передайте их другим направлениям.

Другие правила:

  1. Убедитесь, что вы сохраните объект в хранилище до получения идентификатора объекта. Пока они не сохранены, они временны, и вы не можете получить к ним доступ из другого потока.
  2. Остерегайтесь политик объединения, если вы вносите изменения в управляемые объекты из более чем одного потока.
  3. Полезно.

Но позвольте мне повторить, пожалуйста, внимательно прочитайте документ! Это действительно стоит!

+1

Я нашел отличный пример объединения контекстов в CoreDataBooks (mergeChangesFromContextDidSaveNotification). спасибо. Имейте славный день. Paolo aka SlowTree – SlowTree

+0

О, слава богу. Я читаю это, решил свои проблемы. Импортировал большой набор данных в фоновый поток и получал множество непредсказуемых исключений. Создавать контекст в фоновом потоке, а не передавать его, хотя, похоже, исправили мои иссы. – tobyc

+2

Этот документ еще не обновлен, чтобы воспользоваться очень важными улучшениями в iOS 5 - видео, на которое я ссылаюсь в своем ответе, теперь является лучшей ссылкой. – JosephH

2

Надеюсь, это поможет всем народам, которые сталкиваются с проблемами с использованием основных данных в многопоточной среде.

Взгляните на «Лучшие песни 2» в документации на яблоко. С помощью этого кода я взял «красную таблетку» Matrix и обнаружил новый мир без двойной ошибки и без ошибок. : D

Надеюсь, это поможет.

Paolo

p.s. Огромное спасибо Юджи, в документации, описанной выше, я нашел этот пример.

73

В настоящее время [май 2015 г.] Apple Concurrency with Core Data documentation в лучшем случае очень вводит в заблуждение, поскольку он не охватывает какие-либо улучшения в iOS 5 и, следовательно, больше не показывает наилучшие способы одновременного использования данных ядра.Есть два очень важных изменения в iOS 5 - родительские контексты и новые типы параллелизма/потоков.

Я еще не нашел письменной документации, которая всесторонне охватывает эти новые функции, но WWDC 2012 video "Session 214 - Core Data Best Practices" все это очень хорошо объясняет.

Magical Record использует эти новые функции и может стоить того.

Настоящие основы все те же: вы все же можете использовать только управляемые объекты, в которые был создан поток, на котором был создан контекст управляемого объекта.

Теперь вы можете использовать [moc executeBlock:] для запуска кода в правой нити.

Нет необходимости использовать 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 ...> 
    } 
}]; 
+0

Ссылка WWDC кажется неправильной, хотя .. – Philip007

+7

Upvote для up-to -date info. SO должен внедрить механизм для продвижения ответов, связанных с развитием новых технологий, и преуменьшить эти устаревшие принятые ответы. Благодарим за рекомендацию Magic Record. Его документация выглядит очень красиво. Возможно, я попробую позже. – Philip007

+0

Вопреки фрагменту кода UIManagedDocument по умолчанию создает свой родительский контекст в частной очереди и дочерний контекст в основной очереди. Любая идея, почему Apple делает это? Это абсолютно произвольно? – Philip007

Смежные вопросы