Нарушение многопоточности все, что нам остается, это честь (провал) - PullRequest
0 голосов
/ 02 марта 2019

Я бился 2 дня с этим обвинением разработчиков и себя.Поэтому я попытался упростить пример и попытаться понять этот флаг:

  1. Я создал основной проект данных из мастера (приложение с подробной информацией)
  2. Добавил флаг кАргументы: -com.apple.CoreData.ConcurrencyDebug 1
  3. Добавлен простой код в методе viewDidLoad:

    NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Event"];
    _events = [self.pc.viewContext executeFetchRequest:fr error:nil];
    Event *event = _events.firstObject;
    
    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
    NSManagedObjectID *objID = [event objectID];
    [opQueue addOperationWithBlock:^{
        NSManagedObjectContext *context = self.pc.newBackgroundContext;
        Event *bgEvent = [context objectWithID:objID]; // Thread 5: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    }];
    
  4. Запустил приложение и получил этот сбой (проверьте комментарий на 1 строку раньшепоследнее)

Итак, я пытаюсь переместить основной объект MOC в фоновый MOC, и он падает.

Я что-то упускаю при передаче объектов между MOC вразные потоки?

ПРИМЕЧАНИЕ: pc - это просто persistentContainer, созданный мастером и сохраненный в этом свойстве контроллера strong.И да, у него есть магазины и правильный URL, все хорошо, что если я удалю этот кусок кода, приложение не будет аварийно завершено.Я добавил этот код после того, как добавил несколько строк к сущности Event, чтобы я мог получать объекты.

1 Ответ

0 голосов
/ 02 марта 2019

Вы не можете работать с NSManagedObjectContext в произвольной очереди.Вам нужно использовать очередь контекста.Это означает, что ваш вызов будет objectWithID: в context.perform() (асинхронный) или context.performAndWait() (синхронизация).

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

См. Руководство по программированию основных данных: параллелизм для получения полной информации.


Из ваших комментариев,Вы написали следующее:

NSManagedObjectID *objID = [event objectID];
[self.pc.viewContext performBlockAndWait:^{ 
   NSManagedObjectContext *context = self.pc.newBackgroundContext;
   Event *bgEvent = [context objectWithID:objID]; 
}];

Это неверно, и причина вашей проблемы.Вы не можете использовать context в очереди viewContext.Я полагаю, что вы имеете в виду здесь:

NSManagedObjectID *objID = [event objectID];
NSManagedObjectContext *context = self.pc.newBackgroundContext
[context performBlock:^{
    Event *bgEvent = [context objectWithID:objID]; 
    ....
}];

Вам необходимо использовать context внутри собственного perform block, а не блока perform какого-либо другого контекста.

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

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