Подтвердить что ты не робот

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

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

  • Запустить новый поток
  • Получить новые данные с сервера
  • Создание нового управляемого объекта Контекст
  • Отправьте уведомление в основной поток, чтобы объединить два контекста.

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

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

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

My Entity - действительно простой список атрибутов и отношений.

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

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

ОБНОВЛЕНИЕ 1

Теперь проблема ясна. Контекст 2 имеет большую разницу: ObjectID. Хотя контекст основного потока извлекал ManagedObjects с координатором Persistent Store, второй поток создает этот объект, выбирая удаленный URL. Даже если объекты имеют одинаковое содержимое, они будут иметь 2 разных объекта id.

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

4b9b3361

Ответ 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: для извлечения объекта, связанного с конкретным идентификатором, обновления и сохранения контекста. Теперь слияние будет действовать, как вы ожидаете. В качестве альтернативы, если вы заранее не знаете, какие идентификаторы управляемых объектов должны быть переданы между потоками, то в другом потоке вы просто извлекаете объекты с использованием предиката для получения тех, которые соответствуют объектам, полученным с сервера, затем вы их обновляете и сохраните контекст.