Добавление в UIManagedDocument из фоновой очереди GCD?

Я создаю и добавляю несколько управляемых объектов в Core Data из фоновой очереди. Насколько я понял, я не мог получить доступ к контексту из фонового потока, поэтому я использовал PerformBlock, чтобы запланировать добавление к Core Data обратно в ту же очередь, в которой был создан контекст. Это прекрасно работает...

Мой вопрос: во время тестирования я заметил, что после удаления [moc performBlock:^{ ... }]; приложение по-прежнему работает так, как ожидалось (возможно, даже на доли секунды быстрее). Нужен ли мне performBlock? Я бы предположил, что да, и он просто работает (на данный момент :) не в потокобезопасном режиме, я просто хотел проверить, чтобы убедиться, что мое понимание не ошибочно.

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(backgroundQueue, ^{ 
    // GET DATA
    // PROCESS DATA
    NSManagedObjectContext *context = [[self managedDocument] managedObjectContext];
    [moc performBlock:^{
          // ADD TO CORE DATA
          [Core createRodInContext:context withDictionary:fuelRodDictionary];
     }];

});

EDIT: добавлена ​​реализация для createRodInContext...

+ (Rod *)createRodInContext:(NSManagedObjectContext *)context withDictionary:(NSDictionary *)dictionary {

    // CREATE
    Rod *rod = [NSEntityDescription insertNewObjectForEntityForName:@"Rod" inManagedObjectContext:context];

    // POPULATE
    [neo setDataCode:[dictionary objectForKey:@"dataCode"]];
    [neo setDataName:[dictionary objectForKey:@"dataName"]];
    [neo setDataReference:[dictionary objectForKey:@"dataReference"]];
    ...
    return rod;
}

person fuzzygoat    schedule 21.11.2012    source источник
comment
Разве это не PerformBlock: выполнять операции в фоновом потоке. Если да, то почему вы снова используете блок gcd поверх него.   -  person Sandeep    schedule 22.11.2012
comment
в приведенном выше примере UIDocument (и, следовательно, контекст управляемого объекта) создаются в основном потоке. Приведенный выше код выполняется в фоновом потоке с использованием dispatch_async. При использовании Core Data важно отметить, что контекст управляемого объекта не является потокобезопасным и доступен только в том потоке, в котором он был изначально создан. [moc PerformBlock:^{}]; выполняет указанный блок в потоке, в котором был создан moc, тем самым устраняя любые потенциальные проблемы с потоками.   -  person fuzzygoat    schedule 22.11.2012
comment
Можете ли вы опубликовать реализацию createRodInContext:. В этом методе лежит ключ к тому, почему он работает или не работает.   -  person jackslash    schedule 25.11.2012
comment
Добавлена ​​реализация для createRodInContext: на самом деле это довольно просто, просто простая вставкаForEntityName: и затем заполнение нескольких атрибутов из предоставленного словаря. Примечание. На данном этапе я не использую возвращенный стержень, я, вероятно, удалю его позже, так как не думаю, что он мне понадобится.   -  person fuzzygoat    schedule 25.11.2012


Ответы (1)


В фоновом потоке вы должны использовать [moc performBlock:^{ ... }] для вставки (и заполнения) управляемого объекта в основном контексте управляемого объекта.

Отсутствие performBlock означает, что вы используете контекст управляемого объекта (который был создан в основном потоке) также в другом потоке (который связан с фоновой очередью).

Это может сработать случайно, но как только основной поток обращается к MOC в тот же момент, что и ваш фоновый поток, результаты становятся непредсказуемыми, потому что (как вы уже сказали) MOC не является потоком. сейф.

См. также Параллелизм Поддержка контекстов управляемых объектов в Примечаниях к выпуску основных данных для OS X v10.7 и iOS 5.0:

Конфайнмент (NSConfinementConcurrencyType).

Это значение по умолчанию. Вы обещаете, что контекст не будет использоваться никаким потоком, кроме того, в котором вы его создали.

Но и для других типов параллелизма (частная очередь, основная очередь) вам всегда нужно использовать performBlock (или performBlockAndWait), если только ваш код уже не выполняется в очереди, связанной с MOC.

person Martin R    schedule 25.11.2012
comment
Спасибо, Мартин, это то, о чем я думал. Мне было трудно найти какую-либо информацию об этом, и я просто хотел убедиться, что я все делаю правильно. Кажется, что я, и использование PerformBlock: из фонового потока правильно. Очень признателен ... - person fuzzygoat; 25.11.2012