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

Как скопировать или переместить NSManagedObject из одного контекста в другой?

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

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

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

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

4b9b3361

Ответ 1

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

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

Update

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

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

Как уже упоминалось, вы можете загрузить образец кода из моей книги из "Основная карта программных программистов" и увидеть одно решение этой проблемы, Конечно, в книге я более подробно ее обсуждаю:)

Ответ 2

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

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

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

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

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

Ответ 3

Сама та же проблема и нашла эту статью на созданных отключенных сущностях, которые впоследствии могут быть добавлены в контекст: 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 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;
}

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

Ответ 4

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

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