Каким может быть потокобезопасный способ сохранения контекстной формы Core Data?

У меня NSOperationQueue установлено на NSOperationQueueDefaultMaxConcurrentOperationCount. Он заполнен NSOperation объектами (пока ничего странного). Я создал подкласс NSOperation для выполнения некоторых фоновых задач.

  1. Скачать данные из интернета.
  2. Проанализируйте данные, чтобы я мог их прочитать.
  3. Создайте NSManagedObject:

    [NSEntityDescription insertNewObjectForEntityForName:@"Channel" inManagedObjectContext:context];

  4. Сохраните его с контекстом.

    [сохранение управляемого контекста объекта: и ошибка]

Мне нравится, когда все это происходит в фоновом режиме, поэтому пользовательский интерфейс не блокируется. Я прочитал эта статья о параллелизме с основными данными, насколько я понял. Лучшим способом было бы создать новый NSManagedObjectContext в каждом NSOperation, но совместно использовать один и тот же координатор постоянного хранилища.

Это легко сделать, однако, когда дело доходит до сохранения контекста, в документации говорится, что это может привести к ошибкам. Итак, мой вопрос заключается в следующем:

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

  2. Могу ли я безопасно сохранить контекст в NSOperation? Или это действительно плохая практика?

Я надеюсь, что кто-то может пролить свет на этот вопрос, потому что я действительно застрял в данный момент.


person Mark    schedule 12.08.2012    source источник


Ответы (1)


Вам нужно сделать следующее:

  1. Создайте контекст управляемого объекта для каждой NSOperation. Создайте этот новый контекст в основном методе, потому что это происходит, когда он выполняется в правильном потоке.
  2. Назначьте координатора постоянного хранилища контекста.
  3. Создайте наблюдатель для получения NSManagedObjectContextDidSaveNotification. Это единственный способ узнать основной контекст во время внесения изменений в контекст NSOperation. Убедитесь, что вызов слияния выполняется в потоке/блоке, в котором находится контекст слияния. Если вы объединяетесь с контекстом основного потока, вызовите метод mergeChangesFromContextDidSaveNotification: в основном потоке с уведомлением из контекста NSOperation.

Кроме того, спросите себя, действительно ли вы хотите, чтобы все эти операции работали одновременно. Согласно документации:

Максимальное количество операций по умолчанию определяется динамически объектом NSOperationQueue на основе текущих системных условий.

Вы не можете контролировать, сколько NSOperations будет работать одновременно. Если это не то, что вы хотите, вам может быть лучше, если вы просто перейдете к последовательному NSOperationQueue (maxConcurrentOperation=1), учитывая тот факт, что вы собираетесь блокировать базу данных для сохранения, а также потому, что у вас есть сеть. сделано также.

Вы можете безопасно сохранить внутри основного метода NSOperation, если примете меры предосторожности, упомянутые выше.

person J2theC    schedule 13.08.2012
comment
Большое спасибо, что вы нашли время, чтобы написать это объяснение, признателен. Это очень сложно для меня. Я собираюсь изучить ваш ответ. - person Mark; 13.08.2012
comment
Я знаю, что maxConcurrentOperation==1 дает мне больше контроля, однако некоторые URL-адреса могут загружаться быстрее, чем другие URL-адреса, и с NSOperationQueueDefaultMaxConcurrentOperationCount я уверен, что получу данные максимально быстро. - person Mark; 13.08.2012
comment
У вас может быть очередь последовательной отправки внутри NSOperation, совместно используемая этими экземплярами NSOperation, и использовать эту очередь для обработки сохранения базы данных. Обратите внимание, что для правильной безопасной обработки данных с основными данными вам потребуется создать NSManagedObjectContext и выполнить вызовы вставки NSEntityDescription внутри блока, который вы передаете в последовательную очередь. - person J2theC; 13.08.2012