Cocoa 如何将NSManagedObject从一个上下文复制或移动到另一个上下文?
我假设有一个相当标准的设置,一个scratchpad MOC从未保存(包含从web下载的一堆对象),另一个永久MOC保存对象。当用户从scratchMOC中选择要添加到其库中的对象时,我想1)从scratchMOC中删除该对象并插入到permanentMOC中,或者2)将该对象复制到permanentMOC中。上面说我可以复制这样的对象:Cocoa 如何将NSManagedObject从一个上下文复制或移动到另一个上下文?,cocoa,cocoa-touch,core-data,nsmanagedobject,nsmanagedobjectcontext,Cocoa,Cocoa Touch,Core Data,Nsmanagedobject,Nsmanagedobjectcontext,我假设有一个相当标准的设置,一个scratchpad MOC从未保存(包含从web下载的一堆对象),另一个永久MOC保存对象。当用户从scratchMOC中选择要添加到其库中的对象时,我想1)从scratchMOC中删除该对象并插入到permanentMOC中,或者2)将该对象复制到permanentMOC中。上面说我可以复制这样的对象: NSManagedObjectID *objectID = [managedObject objectID]; NSManagedObject *copy =
NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];
(在本例中,context2将是permanentMOC。)但是,当我这样做时,复制的对象出现故障;数据最初未解析。当它得到解决后,所有的值都是零;原始managedObject中的任何数据(属性或关系)都不会被实际复制或引用。因此,我看不出使用此objectWithID:方法与使用insertNewObjectForEntityForName:将一个全新的对象插入permanentMOC之间有什么区别
我意识到我可以在permanentMOC中创建一个新对象,并从旧对象手动复制每个键值对,但我对这个解决方案不太满意。(我有许多不同的托管对象,我遇到了这个问题,所以我不想在继续开发时编写和更新copy:methods,用于所有这些对象。)有更好的方法吗 您需要确保您正在保存
managedObject
所在的上下文。为了在不同的上下文中获取相同的对象,它需要存在于持久存储中
根据,
objectWithID:
始终返回一个对象。因此,故障解析为对象的事实将显示所有nil
值,这意味着它在持久存储中找不到您的对象。您需要确保保存managedObject
所在的上下文。为了在不同的上下文中获取相同的对象,它需要存在于持久存储中
根据,
objectWithID:
始终返回一个对象。因此,故障解析为对象的事实将显示所有nil
值,这意味着它在持久存储中找不到您的对象。文档具有误导性且不完整。objectID方法本身并不复制对象,它们只是保证您得到了所需的特定对象
示例中的context2
实际上是源上下文,而不是目标。您得到的是nil,因为目标上下文没有具有该ID的对象
由于对象图的复杂性以及上下文管理图的方式,复制托管对象相当复杂。您必须在新上下文中详细地重新创建复制的对象
我从示例代码中剪下的。(您可以下载整个项目代码,而无需在实用网站上购买该书。)它应该能让您大致了解如何在上下文之间复制对象
您可以创建一些复制对象的基本代码,但每个对象图关系的细节通常意味着您必须为每个数据模型进行自定义 文件具有误导性且不完整。objectID方法本身并不复制对象,它们只是保证您得到了所需的特定对象 示例中的
context2
实际上是源上下文,而不是目标。您得到的是nil,因为目标上下文没有具有该ID的对象
由于对象图的复杂性以及上下文管理图的方式,复制托管对象相当复杂。您必须在新上下文中详细地重新创建复制的对象
我从示例代码中剪下的。(您可以下载整个项目代码,而无需在实用网站上购买该书。)它应该能让您大致了解如何在上下文之间复制对象
您可以创建一些复制对象的基本代码,但每个对象图关系的细节通常意味着您必须为每个数据模型进行自定义 首先,在一个线程上有多个
NSManagedObjectContext
不是标准配置。99%的情况下,你只需要一个上下文,这将为你解决这个问题
为什么您觉得需要不止一个NSManagedObjectContext
更新
这实际上是我见过的少数几个有意义的用例之一。为此,需要将对象从一个上下文递归复制到另一个上下文。工作流程如下:
-dictionaryWithValuesForKeys
和-[NSEntityDescription attributesByName]
执行此操作-setValuesForKeysWithDictionary
)-[NSEntityDescription relationshipsByName]
正如另一位所提到的,您可以从我的书中下载示例代码,并查看此问题的一种解决方案。当然,在本书中我将更深入地讨论此问题:)首先,在单个线程上有多个
NSManagedObjectContext
不是标准配置。99%的情况下,你只需要一个上下文,这将为你解决这个问题
为什么您觉得需要不止一个NSManagedObjectContext
更新
这实际上是我见过的少数几个有意义的用例之一。要做到这一点,您需要从一个上下文执行对象的递归复制
+ (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;
}
// `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
}
}