Почему я получаю ошибку слияния при сохранении NSManagedObjectContext в этом «чистом»? - PullRequest
3 голосов
/ 27 января 2011

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

Я работаю над основным приложением данных, в котором сущности имеют отношения родитель / потомок.Приложение создает NSManagedObjectContext (MOC) при запуске.Когда приложение запускается в первый раз, оно использует асинхронный блок для импорта содержимого plist во второй MOC (корневой узел получается из основного MOC, используя URI и -managedObjectIDForURIRepresentation :), непосредственно перед тем, как блок завершает егосохраняет второй контекст.

В моем контроллере данных я подписываюсь на NSManagedObjectContextDidSaveNotification, и при отправке уведомления запускается следующий код:

- (void)backgroundContextDidSave:(NSNotification *)notification {
    if(![notification.object isEqual:self.managedObjectContext]){
        if (![NSThread isMainThread]) {
            [self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
                                   withObject:notification
                                waitUntilDone:NO];
            return;
    }       
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];        ;
    }
}

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

Когда это закончится, я запускаю следующий код, который находится в методе подкласса NSManagedObject:объекты принадлежат, это просто означает удалить дочерний элемент от его родителя:

TreeEntry *oldParent=self.parent; //keep a pointer to the old parent around so we can delete self from the children

// These next four lines are a sanity check to make sure that both objects are on the same MOC we're saving
NSManagedObjectContext *selfContext=self.managedObjectContext;
NSManagedObjectContext *parentContext=self.parent.managedObjectContext;
NSManagedObjectContext *sharedContext=[[DataController sharedDataController] managedObjectContext];
assert([selfContext isEqual:parentContext] && [selfContext isEqual:sharedContext]);

// now we fault the two objects to make sure we can not possibly have them or any changes 
// to them in the state of the main MOC, by this time the second MOC is long gone
[sharedContext refreshObject:self.parent mergeChanges:NO];
[sharedContext refreshObject:self mergeChanges:NO]; 

// up to this point, sharedContex.insertedObjects, sharedContext.updatedObects and sharedContext.deletedObjects
// have all contained no objects at all. None of the above was necessary as the MOC held no changes at all
[sharedContext saveChanges]; // we save it to, well, just to make sure I guess, I may be going crazy

// Now we carry out two changes to the objects, problem occurs if only one change is carried out,
// I'm showing both to show that there relationship is being kept consistent and valid
self.parent=nil;
[oldParent removeChild:self];


// When the next line is run the save fails with a merge conflict
[sharedContext saveChanges];

Последнее сохранение завершается неудачно с ошибкой Какао 133020, которая является ошибкой слияния.Два NSMergeConflicts в ошибке относятся к записям, с которыми мы имеем дело (self и self.parent).

Я просто не понимаю, как это может быть.Объекты не имеют состояния, когда они модифицируются, поэтому они ДОЛЖНЫ загружаться из магазина.Вносятся два простых изменения, а затем, когда они сохраняются сразу после этого, возникает конфликт слияния.Как это может быть?больше ничего не запуталось с хранилищем, и мы только что загрузили из него объекты.

Я знаю, что могу изменить политику слияния, но я не хочу этого делать, не понимая, что происходит.

Есть идеи?Я уверен, что это просто моя ментальная модель, если то, что происходит, неверно, но я не смог исправить это весь день!

1 Ответ

7 голосов
/ 10 февраля 2011

Хорошо, это было фундаментальное недоразумение с моей стороны о том, как работает фреймворк, или, если быть более точным, кэш NSManagedStoreCoordinator.

Когда я сохраняю фоновый контекст, изменения переходят на диск, но, очевидно, NSManagedStoreCoordinator (который разделяют оба контекста) не обновляет и не делает недействительным свой кэш.

Когда я обновляю объекты в основном MOC, данные, используемые для их повторного заполнения, поступают из кэша, в котором все еще хранятся старые данные. Он не перезагружается с диска. Решением было использовать [MOC setStalenessInterval: 0.0] для принудительной перезагрузки с диска.

...