Основные данные слияния двух управляемых объектов контекста


Мой Cocoa / Application имеет контекст управляемого объекта в главном потоке. Когда мне нужно обновить мои данные, моя программа будет:

  1. запуск нового потока
  2. Получение новых данных с сервера
  3. Создайте новый контекст управляемого объекта
  4. отправить уведомление в основной поток, чтобы объединить два контекста

Это функция, которая получает уведомление по основному потоку

- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification
{
    if ([NSThread isMainThread]) {
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
    } else {
        [self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];     
    }
}

Я не получаю никаких ошибок. Моя проблема-результат слияния, он фактически объединяет управляемые объекты из обоих контекстов.

Моя сущность-это действительно простой список атрибутов и отношений.

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

Мне просто нужно понять, как правильно объединить 2 контекста, чтобы иметь одну обновленную копию для каждого объекта.

Обновление 1

Теперь эта проблема мне ясна. Контекст 2 имеет большое различие: ObjectID. В то время как контекст в главном потоке извлекает объекты ManagedObjects с помощью координатора постоянного хранилища, второй поток создает эти объекты, извлекая удаленный URL-адрес. Даже если ... объекты имеют одинаковое содержание, они будут иметь 2 различных objectID.

Мои объекты уже имели уникальный идентификатор, я мог использовать setObjectId для установки этого значения. (Документация Apple говорит, что это не очень хорошая идея).

1 22

1 ответ:

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

NSManagedObjectContextDidSaveNotification

, следовательно, все, что вам нужно сделать, это:

1) в вашем основном потоке, возможно, в методе viewDidLoad, зарегистрируйте это уведомление:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(contextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                            object:nil];

2) реализуйте метод contextDidSave: в главном потоке следующим образом:

- (void)contextDidSave:(NSNotification *)notification
{

    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
    [managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES];

}

3) в вашем dealloc метод добавить следующее:

[[NSNotificationCenter defaultCenter] removeObserver:self];
4) Создайте новый контекст в другом потоке, используя что-то вроде следующего метода:
- (NSManagedObjectContext*)createNewManagedObjectContext
{

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    [moc setUndoManager:nil];
    return [moc autorelease];
}
5) при получении новых данных правильным способом обработки этой ситуации является использование идентификаторов управляемых объектов. Поскольку идентификаторы управляемых объектов потокобезопасны, их можно передавать из основного потока в другой поток, а затем использовать existingObjectWithID:error: для извлечения объекта, связанного с определенным идентификатором, обновления его и сохранения контекста. Теперь слияние будет действовать следующим образом: вы ожидаете. Кроме того, если вы заранее не знаете, какие идентификаторы управляемых объектов должны передаваться между потоками, то в другом потоке вы просто извлекаете объекты, используя предикат, чтобы получить те, которые соответствуют объектам, полученным с сервера, затем вы обновляете их и сохраняете контекст.