Нужно ли родительскому элементу Core Data ManagedObjectContext совместно использовать тип параллелизма с дочерним контекстом? - PullRequest
23 голосов
/ 08 декабря 2011

Могу ли я установить родительский контекст моего ManagedObjectContext в ManagedObjectContext с другим типом параллелизма?Например:

backgroundManagedObjectContext_ = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundManagedObjectContext_ setPersistentStoreCoordinator:coordinator];
managedObjectContext_ = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext_ setParentContext:backgroundManagedObjectContext_];

Моя цель - (надеюсь) получить быстрое сохранение для управляемогоObjectContext_ (так как ему нужно только сохранить вещи в родительском контексте в памяти), а затем сделать backgroundManagedObjectContext_ сохранить насвоя очередь.Если мне не понадобится сделать еще одно сохранение из очереди «переднего плана», прежде чем фоновое сохранение будет сохранено, мой пользователь никогда не увидит долгое время сохранения.

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


Подробности для одного места, где я могу более или менее надежно создать тупик:

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

У меня есть несколько типов сущностей (около 5), каждый содно или два двунаправленных отношения с другим объектом.

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

Поэтому, когда я вижу пустую базу данных (это проверяется в основном потоке), я добавляю около 4 или 8 из всех, кроме одного типа сущностиs, и этот последний получает около 100 (все добавления происходят в главном потоке).Основной поток делает saveContext.После этого (без ошибок) он просит другой контекст управляемого объекта запустить блок, который также выполняет saveContext.Этот saveContext определенно является тупиковым участником.Это также ЕДИНСТВЕННАЯ штука, сделанная с "фоновым" NSManagedObjectContext вообще.

Точный поток управления после этого немного мутный, как NSFetchedResultsController (все с заданным типом сущности (который имеет ~ 3 члена)с простой сортировкой и размером пакета около 20) управляют следующим циклом активности Core Data, но из TableViewController вызывается запрос, сколько элементов ему нужно управлять, а именно, «сколько результатов выбирает контроллер результатов выборкииметь".Этот звонок - другая сторона тупика.(все это в основной ветке)

1 Ответ

36 голосов
/ 10 декабря 2011

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

В недавнем проекте у меня был родитель NSManagedObjectContext, который поддерживал NSFetchedResultsController, созданный с помощью NSMainQueueConcurrencyType. Оттуда я создал NSManagedObjectContext с NSPrivateQueueConcurrencyType и установил контекст с NSMainQueueConcurrencyType в качестве родителя. Теперь мой дочерний контекст может содержать недопустимые правки при добавлении нового объекта, который в конечном итоге окажется в табличном представлении, поддерживаемом NSFetchedResultsController, который поддерживается родительским контекстом. Когда я был готов сохранить свои изменения и передать их в родительский контекст, код выглядел следующим образом.

// Save the child context first
[childContext performBlock:^{
    NSError *error = nil;
    [childContext save:&error];

    // Save the changes on the main context
    [parentContext performBlock:^{
        NSError *parentError = nil;
        [parentContext save:&parentError];
    }];
}];

Теперь я не могу с уверенностью сказать, что это правильный способ сделать это, потому что документация по этому вопросу довольно скудна на данный момент. Было бы полезно, если бы вы могли показать какой-то код, который, по вашему мнению, вызывает взаимные блокировки. Если вы участвуете в программе для разработчиков, вы можете посмотреть видео сессий WWDC, посвященных основным данным этого года. Я считаю, что есть два, один для Mac OS X и один для iOS, которые в основном касаются одних и тех же идей, но каждый из них также содержит уникальную информацию.

...