Базовые данные объединяют два контекста управляемых объектов - PullRequest
22 голосов
/ 05 августа 2011

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

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ 1

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

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

1 Ответ

33 голосов
/ 05 августа 2011

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

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

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