2016-02-08 2 views
0

Я новичок в CoreData, и я пытаюсь создать простое приложение.iOS: Синхронизация доступа к CoreData

Предположим, у меня есть функция:

func saveEntry(entry: Entry) { 
    let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType) 
    moc.parentContext = savingContext 

    moc.pefrormBlockAndWait { 
    // find if MOC has entry 
    // if not => create 
    // else => update 
    // saving logic here 
    } 
} 

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

func saveEntry(entry: Entry) { 
    dispatch_sync(serialDbQueue) { // (1) 
     let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType) 
     moc.parentContext = savingContext 

     moc.pefrormBlockAndWait { // (2) 
      // find if MOC has entry 
      // if not => create 
      // else => update 
      // saving logic here 
     } 
    } 
} 

И это работает отлично, пока я не хотел бы добавить еще одну функцию интерфейса:

func saveEntries(entries: [Entry]) { 
    dispatch_sync(serialDbQueue) { // (3) 
     let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType) 
     moc.parentContext = savingContext 

     moc.pefrormBlockAndWait { 
      entries.forEach { saveEntry($0) } 
     } 
    } 
} 

А теперь я имеют тупик: 1 будет вызываться в serialDbQueue и ждать завершения сохранения. 2 будет вызываться в частной очереди и будет ждать 3. И 3 ждет 1.

Итак, каков правильный способ обработки синхронизирующего доступа? Насколько я понимаю, небезопасно сохранять один MOC и выполнять его с сохранением по причинам, описанным здесь: http://saulmora.com/coredata/magicalrecord/2013/09/15/why-contextforcurrentthread-doesn-t-work-in-magicalrecord.html

+0

Вы уверены, что необходима очередность очереди? Почему включение двух операций с помощью 'performBlockAndWait' вызывает проблему для вас, если вы выполняете свою проверку опрокидывания внутри этого блока? – Jonah

+0

@ Jonah да, я. Если я запустил все со значком MOC - все в порядке. Но, как вы видите, 'saveEntry' создает MOC для каждого вызова. Итак, у вас будут параллельные операции – user1284151

+0

К сожалению, я должен был внимательно прочитать. Вместо последовательной очереди для создания многих mocs, почему бы не разделить moc, который будет действовать как эта очередь? – Jonah

ответ

1

Я попытался бы реализовать это с помощью одного NSManagedObjectContext в качестве механизма управления. Каждый контекст поддерживает очередность последовательной работы, поэтому несколько потоков могут вызывать performBlock: или performBlockAndWait: без какой-либо опасности одновременного доступа (хотя вы должны быть осторожны в изменении данных контекста между временем, в течение которого блок находится в очереди и когда он в конечном итоге выполняется). Пока все работы в контексте выполняются в правильной очереди (через performBlock), нет никакой неотъемлемой опасности при запуске работы из нескольких потоков.

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

  • Какой объект будет отвечать за создание этого контекста и как он будет доступен для каждого объекта, который в нем нуждается?
  • С общим контекстом становится трудно узнать, когда работа над этим контекстом «завершена» (это операционная очередь пуста), если это представляет собой содержательное состояние в вашем приложении.
  • В общем контексте сложнее отказаться от изменений, если вы хотите отменить несохраненные изменения в случае ошибки (вам нужно будет фактически отменить эти изменения, а не просто отбрасывать контекст без сохранения).
+0

Большое спасибо! У меня есть указатель DB, который содержит всю логику, связанную с сохранением записи. Я предполагаю, что он создаст частный контекст и выполнит все изменения на нем. Вы уверены, что безопасно поддерживать контекст знака и выполнять все изменения на нем (несмотря на то, что Саул Мора упомянул)? – user1284151

+0

@ user1284151 Saul обращается к реальной, но не связанной с этим проблеме. Первоначально исходные данные основывались на «NSConfinementConcurrencyType» на ограничение потока на «NSManagedObjectContext», но существуют ограничения на то, как оптимизировать параллелизм на основе потоков.Предпочитаемый шаблон, теперь принятый MagicalRecord, заключается в использовании ограничения в очереди, которое не обязательно связывает контекст с одним потоком. Таким образом, «contextForCurrentThread» MagicalRecord больше не является полезным или действительным. В обеих моделях общий контекст действителен в пределах ограниченных ограничений. – Jonah

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