Ошибка параллелизма с CoreData и отношением один ко многим - PullRequest
0 голосов
/ 28 марта 2012

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

Следуя Рекомендации Apple по этому вопросу, у меня есть 2 разныхконтексты управляемого объекта (один для основного потока, один для фонового потока).Вот код распределения (в моем делегате приложения):

// Object context for Main Thread
_managedObjectContext = [[NSManagedObjectContext alloc] init];
_managedObjectContext.persistentStoreCoordinator = _coordinator;

// Object context for the background thread
dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(
    myGroup,
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
    ^{
        _bgManagedObjectContext = [[NSManagedObjectContext alloc] init];
        _bgManagedObjectContext.persistentStoreCoordinator = _coordinator;
    }
);

dispatch_group_wait(myGroup, DISPATCH_TIME_FOREVER);
dispatch_release(myGroup);

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

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

NSURLRequest *request = [NSURLRequest requestWithURL:webserviceURL];
AFHTTPRequestOperation *operation =
        [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];

[operation setCompletionBlockWithSuccess:
    ^(AFHTTPRequestOperation *operation, id responseObject) {
        // Getting the managed object context created on the bg thread
        NSManagedObjectContext *context = [self bgManagedObjectContext];

        //
        // Snip...
        // Fetch objects, update them
        //

    } failure:nil];

operation.successCallbackQueue =
        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
[operation start];

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

Моя основная сущность (Place) определяет одностороннее отношение один-ко-многим к Keyword(полнотекстовый поиск бедняка ...) и когда я переиндексирую Place, я начинаю с удаления всех связанных Keyword с.

// `self.searchWords` is a @dynamic property
for (NSManagedObject *word in self.searchWords) {
    // context is still the background thread's object context
    // and we're still on the background thread
    [context deleteObject:word];
}
[self removeSearchWords:oldSearchWords];

При достижении [context deleteObject:word], я 'получаю исключение: NSManagedObjectContext не может удалять объекты в других контекстах

Когда я отлаживаю и проверяю переменные, я вижу, что:

  • self._cd_managedObjectContextконтекст объекта фонового потока
  • word._cd_managedObjectContext является контекстом объекта основного потока

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

Я мог бы в итоге повторно извлечь связанный Keyword в фоновом контексте, а затем удалить его отсюда, но является ли это единственным решением в этом случае?Или я что-то не так делаю?

1 Ответ

0 голосов
/ 29 марта 2012

Clément,

Я бы предложил две вещи.Во-первых, фоновые MOC должны быть созданы в потоке, в котором они выполняются.Используя GCD, вы не можете претендовать на какой-либо поток навсегда.Следовательно, это подводит меня ко второму пункту.Не сохраняйте свой фон MOCs.Они дешевы в создании.Я подозреваю, что большая часть вашей проблемы связана с не синхронизацией MOC.Постоянное хранилище - действительно механизм, чтобы сделать это любым способом.

Эндрю

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