55

我有一个我认为是相当标准的设置,一个从不保存的暂存器 MOC(包含从网上下载的一堆对象)和另一个永久的 MOC,它保留对象。当用户从 scratchMOC 中选择一个对象添加到她的库中时,我想要 1)从 scratchMOC 中删除该对象并插入到 PermanentMOC 中,或者 2)将该对象复制到 PermanentMOC 中。Core Data FAQ说我可以像这样复制一个对象:

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

(在这种情况下,context2 将是永久MOC。)但是,当我这样做时,复制的对象出错了;数据最初是未解决的。当它确实得到解决后,所有的值都为零;原始 managedObject 中的任何数据(属性或关系)都不会被实际复制或引用。因此,我看不出使用这个 objectWithID: 方法和使用 insertNewObjectForEntityForName: 将一个全新的对象插入到永久MOC 之间有什么区别。

我意识到我可以在permanentMOC 中创建一个新对象并从旧对象手动复制每个键值对,但我对这个解决方案不太满意。(我有许多不同的托管对象都有这个问题,所以我不想在继续开发时编写和更新所有这些对象的方法。)有更好的方法吗?

4

5 回答 5

56

NSManagedObjectContext首先,在单个线程上拥有多个不是标准配置。99% 的情况下,您只需要一个上下文,这将为您解决这种情况。

为什么你觉得你需要不止一个NSManagedObjectContext

更新

这实际上是我见过的少数几个有意义的用例之一。为此,您需要将对象从一个上下文递归复制到另一个上下文。工作流程如下:

  1. 在持久上下文中创建新对象
  2. 从源对象获取属性字典(使用-dictionaryWithValuesForKeys-[NSEntityDescription attributesByName]来执行此操作。
  3. 将值字典设置到目标对象上(使用-setValuesForKeysWithDictionary
  4. 如果您有关系,您将需要递归地执行此复制并通过硬编码(以避免一些循环逻辑)或使用-[NSEntityDescription relationshipsByName]

正如另一个人所提到的,您可以从The Pragmatic Programmers Core Data Book中的我的书中下载示例代码,并查看此问题的一个解决方案。当然在书中我会更深入地讨论它:)

于 2010-06-09T17:54:10.010 回答
10

该文档具有误导性且不完整。objectID 方法本身并不复制对象,它们只是保证您已获得所需的特定对象。

示例中的context2实际上是源上下文而不是目标。你得到一个 nil 因为目标上下文没有具有该 ID 的对象。

由于对象图的复杂性和上下文管理图的方式,复制托管对象相当复杂。您必须在新上下文中详细重新创建复制的对象。

这是我从The Pragmatic Programmer's Core Data: Apple's API for Persisting Data on Mac OS X的示例代码中截取的一些示例代码。(您可能无需在 Pragmatic 站点购买这本书就可以下载整个项目代码。)它应该让您大致了解如何在上下文之间复制对象。

您可以创建一些复制对象的基本代码,但每个对象图关系的细节通常意味着您必须为每个数据模型进行自定义。

于 2010-06-08T16:41:54.910 回答
7

我自己也有同样的问题,发现这篇关于创建断开连接的实体的文章以后可以添加到上下文中: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;
}

希望有帮助。

于 2012-07-12T13:55:48.887 回答
1

您需要确保保存所在的上下文managedObject。为了在不同的上下文中获取相同的对象,它需要存在于持久存储中。

根据文档objectWithID:总是返回一个对象。因此,故障解决为对象的事实将所有nil值都意味着它没有在持久存储中找到您的对象。

于 2010-06-08T15:27:30.407 回答
1

斯威夫特 5

如果你想知道如何在 2020 年复制 NSManagedObjects,下面的代码对我有用:

// `Restaurant` is the name of my managed object subclass.

// I like to have Xcode auto generate my subclasses (Codegen 
//     set to "Class Definition") & then just extend them with 
//     whatever functionality I need.

extension Restaurant {
    public func copy() -> Restaurant? {
        let attributes = entity.attributesByName.map { $0.key }
        let dictionary = dictionaryWithValues(forKeys: attributes)
        guard let context = AppDelegate.shared?.persistentContainer.viewContext,
            let restaurantCopy = NSEntityDescription.insertNewObject(forEntityName: Restaurant.entityName, into: context) as? Restaurant
            else
        {
            return nil
        }
        restaurantCopy.setValuesForKeys(dictionary)

        return restaurantCopy
    }
}
于 2020-01-30T23:39:55.160 回答