Скажем, у меня есть 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