Как я могу скопировать или переместить NSManagedObject из одного контекста в другой? - PullRequest
51 голосов
/ 08 июня 2010

Я полагаю, что это довольно стандартная установка, с одним MOC блокнота, который никогда не сохраняется (содержащий кучу объектов, загруженных из Интернета), и другим постоянным MOC, который сохраняет объекты. Когда пользователь выбирает объект из scratchMOC для добавления в свою библиотеку, я хочу либо 1) удалить объект из scratchMOC и вставить в перманентный MOC, либо 2) скопировать объект в перманентный MOC. Core Data FAQ говорит, что я могу скопировать объект следующим образом:

NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];

(В этом случае context2 будет перманентным MOC.) Однако, когда я делаю это, копируемый объект становится ошибочным; данные изначально неразрешены. Когда это действительно разрешено, позже все значения равны нулю; никакие данные (атрибуты или отношения) из исходного управляемого объекта не копируются и не ссылаются на них. Поэтому я не вижу никакой разницы между использованием этого objectWithID: метода и просто вставкой совершенно нового объекта в constantMOC с использованием insertNewObjectForEntityForName:.

Я понимаю, что могу создать новый объект в constantMOC и вручную скопировать каждую пару ключ-значение из старого объекта, но я не очень доволен этим решением. (У меня есть несколько различных управляемых объектов, для которых у меня есть эта проблема, поэтому я не хочу писать и обновлять методы copy: для всех из них, поскольку я продолжаю разрабатывать.) Есть ли лучший способ?

Ответы [ 4 ]

52 голосов
/ 09 июня 2010

Во-первых, наличие более одного NSManagedObjectContext в одном потоке не стандартной конфигурации. В 99% случаев вам нужен только один контекст, и это решит эту ситуацию за вас.

Почему вы чувствуете, что вам нужно более одного NSManagedObjectContext?

Обновление

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

  1. Создать новый объект в постоянном контексте
  2. получить словарь атрибутов из исходного объекта (для этого используйте -dictionaryWithValuesForKeys и -[NSEntityDescription attributesByName].
  3. установить словарь значений на целевой объект (используя -setValuesForKeysWithDictionary)
  4. Если у вас есть отношения, вам нужно будет делать эту копию рекурсивно и обходить отношения либо жестко закодировано (чтобы избежать некоторой циклической логики), либо с помощью -[NSEntityDescription relationshipsByName]

Как уже упоминалось, вы можете загрузить пример кода из моей книги из Базового справочника Pragmatic Programmers и увидеть одно решение этой проблемы. Конечно, в книге я обсуждаю это более подробно:)

9 голосов
/ 08 июня 2010

Документация вводит в заблуждение и неполна. Методы objectID сами по себе не копируют объекты, они просто гарантируют, что вы получили нужный объект.

context2 в примере на самом деле является исходным контекстом, а не местом назначения. Вы получаете ноль, потому что целевой контекст не имеет объекта с этим идентификатором.

Копирование управляемых объектов довольно сложное из-за сложности графа объектов и способа управления графом контекстом. Вы должны воссоздать скопированный объект подробно в новом контексте.

Вот пример кода , который я вырвал из примера кода для Основные данные Прагматического программиста: API Apple для хранения данных в Mac OS X . (Возможно, вы сможете загрузить весь код проекта, не покупая книгу на сайте Pragmatic.) Она должна дать вам приблизительное представление о том, как выполнить копирование объекта между контекстами.

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

6 голосов
/ 12 июля 2012

У меня была такая же проблема, и я нашел эту статью о созданных отключенных объектах, которые позже можно было добавить в контекст: http://locassa.com/temporary-storage-in-apples-coredata/

Идея состоит в том, что у вас есть NSManagedObject, потому что вы собираетесь хранить объекты в базе данных. Мое препятствие состояло в том, что многие из этих объектов загружаются через HTTP API, и я хочу выбросить большинство из них в конце сеанса. Подумайте о потоке пользовательских сообщений, а я хочу сохранить только те, которые были добавлены в избранное или сохранены как черновик.

Я создаю все свои сообщения, используя

+ (id)newPost {
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:self.managedObjectContext];
    Post *post = [[Post alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
    return post;
}

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

+ (BOOL)favoritePost:(Post *)post isFavorite:(BOOL)isFavorite
{
    // Set the post's isFavorite flag
    post.isFavorite = [NSNumber numberWithBool:isFavorite];

    // If the post is being favorited and not yet in the local database, add it
    NSError *error;
    if (isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] == nil) {
        [self.managedObjectContext insertObject:post];
    }
    // Else if the post is being un-favorited and is in the local database, delete it
    else if (!isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] != nil) {
        [self.managedObjectContext deleteObject:post];
    }

    // If there was an error, output and return NO to indicate a failure
    if (error) {
        NSLog(@"error: %@", error);
        return NO;
    }

    return YES;
}

Надеюсь, это поможет.

1 голос
/ 08 июня 2010

Необходимо убедиться, что вы сохраняете контекст, в котором живет managedObject. Чтобы получить тот же объект в другом контексте, он должен присутствовать в постоянном хранилище.

Согласно документации , objectWithID: всегда возвращает объект.Таким образом, тот факт, что ошибка разрешается для объекта, будет означать, что все значения nil означают, что он не находит ваш объект в постоянном хранилище.

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