iOS5 CoreData запускает сбои одновременно на родительском и дочернем MOC, вызывая сбой - PullRequest
1 голос
/ 21 февраля 2012

Скажем, у меня есть 4 MOC (контекст управляемого объекта), как это:

rootMOC (сохранение фона) -> fetchMOC (выборка фона) -> mainMOC (связан с пользовательским интерфейсом)

rootMOC -> networkMOC (связанный с сетью)

'A->B' means A is a parent of B.

Итак, рабочий процесс такой:

  • Создание объектов в сети MOC, [OK]
  • Сохранить в rootMOC, [OK]
  • Передать objectIDs в fetchMOC и mainMOC [OK]
  • вызов [moc objectWithID : objectID] [OK]
  • [moc refreshObject : объект mergeChanges: YES ] в fetchMOC & mainMOC для внесения изменений [OK]

  • Позже я получаю доступ к свойству объектов, которые вызывают одновременную ошибку в fetchMOC и mainMOC [Boom, crash!]

В чем я уверен:

  • Все MOC правильно настроены с использованием NSPrivateQueueConcurrencyType или NSMainQueueConcurrencyType .
  • Все вызовы API, связанные с MOC, заключены в executeBlock , даже просто получая доступ к свойству управляемого объекта (что может привести к возникновению ошибки).

Вот код сбоя в потоке 4 ( fetchMOC )

comparator = [^NSComparisonResult(id obj1, id obj2) {
                ArticleInfo* info1 = obj1;
                ArticleInfo* info2 = obj2;
                if (info2.timeStamp > info1.timeStamp) { //[Thread4 fetchMOC:Crash]
                    return NSOrderedAscending;
                } 
                else if (info2.timeStamp == info1.timeStamp) {
                    return NSOrderedSame;
                }
                else {
                    return NSOrderedDescending;
                }
            } copy];

А что между тем происходит в mainMOC:

[self.fetchMOC performBlock:^{
                    [self.fetchMOC refreshObject:self.currentUserFetchMOC mergeChanges:YES];
                    for (Stream* stream in self.currentUserFetchMOC.streams) {
                        [self.fetchMOC refreshObject:stream mergeChanges:YES];
                    }
                    [self.mainMOC performBlock:^{
                        LogMessage(@"MainMOC", 0, @"%@", @"Refresh steams Begin");
                        [self.mainMOC refreshObject:self.currentUserMainMOC mergeChanges:YES];
                        for (Stream* stream in self.currentUserMainMOC.streams) {
                            [self.mainMOC refreshObject:stream mergeChanges:YES];
                            if ([stream.uri isEqualToString:self.currentUserMainMOC.currentStreamURI]) {//Thread 1, here
                                self.currentStreamMainMOC = stream;
                            }
                        }
                        LogMessage(@"MainMOC", 0, @"%@", @"Refresh steams End");
                    }];
                }];

EDIT

ПОЧЕМУ СБОЙ :

После изучения каждой строки моего кода я выясняю, почему. Я проверил, заменив objectWithID существующимObjectWithID, чтобы убедиться, что объекты уже существуют в fetchMOC и mainMOC. Результатом стало большое удивление, что существующий объект Subject вернул ноль. Поэтому я думаю, что причина в том, что [networkMOC save] не сохраняет все синхронно , и я не должен вызывать objectWithID сразу после возвращения сохранения.

* 1089 Временное решение *:

Я просто переместил весь код слияния объектов в обработчик NSManagedObjectContextDidSaveNotification сразу после вызова [fetchMOC mergeChangesFromContextDidSaveNotification], и на этот раз существующийObjectWithID возвращает действительный объект, и без сбоев снова.

Все еще удивляет :

Сессия 303. Что нового в базовых данных на iOS показывает мне, что с помощью вложенных MOC я могу делиться несохраненными изменениями между родственными MOC, и это то, что я пытался реализовать (и мне это не удалось). Насколько я знаю, нет примера кода / блога / видео, показывающего, что именно нужно делать после вызова [sourceMOC save], когда парень из Apple говорит, что просто «извлекает» изменения, просто обращаясь к свойствам управляемых объектов. Очевидно, что не работает только при доступе к свойствам! Хотя работает mergeChangesFromContextDidSaveNotification, это просто СЛИШКОМ МЕДЛЕННО. Я создал тему на форуме разработчиков и пока не получил ответа.

https://devforums.apple.com/message/624382#624382

1 Ответ

0 голосов
/ 22 февраля 2012

Чжао,

Поддержание согласованности между MOC может быть непростым делом.МОС легко создавать и уничтожать.Постоянное хранилище и его координатор предназначены для обеспечения согласованности.Кеш строк очень быстрый.Поэтому я бы порекомендовал вам создавать и уничтожать MOC по мере необходимости.Я подозреваю, что ваша проблема просто исчезнет, ​​когда вы начнете использовать новый MOC для каждой фоновой операции.(В моих приложениях это действительно так.)

Андрей

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