2015-05-31 2 views
0

Мне было интересно, может ли кто-нибудь указать мне в правильном направлении, правильно ли я использую параллелизм. Я нахожу, что в настоящее время код очень громоздкий и почти неинтуитивный. В целях моей демонстрации обратите внимание на то, что архитектура CoreData описана Маркусом Заррой в его статье http://martiancraft.com/blog/2015/03/core-data-stack/. Поскольку операция может занять очень много времени, я хочу, чтобы весь этот процесс выполнялся в фоновом потоке.Я приближаюсь к параллелизму?

NSManagedContext *context = [[NSManagedContext alloc] initWithConcurrency:NSPrivateConcurrencyQueue]; 
context.parentContext = [[CoreDataController sharedDispatch] managedObjectContext]; 
[context performBlock: ^{ 
NSManagedObject *someManagedObject = [[context executeFetchRequest:request error:nil] firstObject]; 
NSString *resultFromLongOperation = [self someLongOperation:someManagedObject]; 
[self doSomething]; 
BOOL anotherResultFromLongOperation = [self aDifferentLongOperation:someManagedObject]; 
}]; 

Так из этого краткого примера, мы можем видеть, что я манипулируя переменной someManagedObject, которая имеет тип NSManagedObject и, следовательно, должны быть использованы в performBlock/performBlockAndWait, как это предписано Apple. Должен ли я проходить в контексте в someLongOperation и aDifferentLongOperation? Если я этого не сделаю, не означает ли это, что мне нужно будет создать еще один дочерний контекст и выполнить все функции, выполняемые внутри executeBlock/performBlockAndWait, и вернуть результат с типом __block? Как насчет того, если результат someLongOperation влияет на реакцию aDifferentLongOperation? Я все еще правильно структурирую свой код для такой ситуации?

Большое спасибо за продвинутый!

+0

Этот вид кода, безусловно, уродливый, но он плотный. Другим подходом было бы использование GCD, что имеет смысл, если у вас много сложных вещей, работающих бок о бок. –

+0

GCD все равно отправит отдельный поток, тем самым нарушив одно правило контекста/потока, установленное Apple. Однако, даже если это было разрешено, как это решает мою проблему? Мне нужно было бы использовать типы переменных __block для получения ответа? –

+0

Вы можете создать очередную очередь и иметь один контекст для этой очереди. Чтобы безопасно связываться между потоками, вы передаете идентификаторы. Таким образом, поток 1 выполняет операцию поиска, находит три объекта, эти объекты нельзя безопасно использовать в другом потоке, но вы можете безопасно передавать их идентификаторы. – gnasher729

ответ

0

Не так давно я боролся с этой проблемой.

Я искал сценарии лучшей практики и обнаружил, что:

  • Вы действительно, как вы заявили, не должен нарушать правила/нити в один контексте, установленные Apple.
  • Обычно вы должны использовать блоки завершения или уведомления с длинными работами, независимо от того, не заставляет ли он замораживать пользовательский интерфейс или просто для ясности кода.
  • Когда вы используете блок завершения, вы можете создать дочерний контекст в своей долгой работе (someLongOperation) и делать с ним все, что хотите.
  • Если ваш результат NSString, тогда у вас не должно быть проблем, потому что это не NSManagedObject и не привязано ни к одному контексту.
  • Если результатом является объект NSManagedObject, вы должны передать его NSManagedObjectID в блок завершения (с помощью метода [managedObject objectID]).
  • Вы можете использовать метод контекста obtainPermanentIDsForObjects, если вы создали новый объект и еще не имеете идентификатор объекта.

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

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

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