【问题标题】:Add an instance of NSManagedObject to NSManagedObjectContext ok, updating the same instance failed将 NSManagedObject 的实例添加到 NSManagedObjectContext ok,更新同一个实例失败
【发布时间】:2011-03-20 17:36:28
【问题描述】:

我在我的 iPhone 应用程序中使用核心数据。我创建了一个简单的类 Friend,它派生自 NSManagedObject,并使用以下属性:

@property (nonatomic, retain) NSString *name;

我可以在我的上下文中添加和删除此类的实例,并且我的更改也是持久的。
现在我想更新/修改一个 Friend-实例并使其再次持久化。

但这似乎不起作用。

这是显示我的问题的一段代码:

//  NSManagedObjectContext *context  = < my managed context> 
//   NSFetchedResultsController *nsfrc= < my fetched result controller>

NSEntityDescription *entity = [nsfrc entity];
NSManagedObject *newManagedObject = [NSEntityDescription 
       insertNewObjectForEntityForName:[entity name]  inManagedObjectContext:context];

Friend *f = (Friend *) newManagedObject;
f.name = @"name1";
//1.  --- here context.hasChanges == 1 ---   ok

NSError *error = nil;
if (![context save:&error]) { ... }
//2.  --- here context.hasChanges == 0 ---   ok

f.name = @"name2";
//3.  --- here context.hasChanges == 0 ---   nok?

if (![context save:&error]) { ... }

在评论 1 中,一切都很好。我得到了一个 Friend 类型的新 NSManagedObject,我可以更改 name 属性。上下文告诉我有一些东西可以保存。 保存上下文后,我看到 context.hasChanges == 0。另请注意,数据在保存上下文后是持久的。

在评论 2 之后,我更改了 name 属性。现在我希望 context.hasChanges == 1 并且在 context save 之后我希望新名称是持久的。 但不幸的是它不是。再次启动应用程序,使用 name-property = @"name1" 加载 Friend 实例。

我在核心数据文档中找不到任何提示或示例。那么我做错了什么? 我需要做什么来更新/修改现有的Friend-实例并使其持久化?

我看到的唯一解决方案是删除条目,更改它,然后再次添加。但我认为这不是正确的方法。

谢谢!

【问题讨论】:

  • 顺便说一句,您不需要强制转换为您的 Friend 对象。由于 -insertNewObjectForEntityForName: inManagedObjectContext: 返回一个 id,您可以简单地将其分配给 Friend*。在 Objective-C 中,99.9% 的时间都不需要强制转换。
  • 感谢您的提示,马库斯。你当然是对的。那是因为我还是不习惯objective-c。

标签: iphone core-data nsmanagedobject nsmanagedobjectcontext


【解决方案1】:

未能识别更改可能是由于您在子类实现中使用@synthesize 而不是@dynamic。 CD 提供了自己的访问器,您可以使用 @synthesize 绕过这些访问器 马丁

【讨论】:

  • 我希望我能投票 10 次。 “upvote”应该是“donate with paypal”按钮。
【解决方案2】:

我唯一能想到的是上下文无法观察 Friend 对象,因为您已将其初始化为通用 NSManagedObject 而不是 Friend 子类的实例。

通用 NSManagedObject 不像它的子类那样在属性中存储值。相反,它使用类似于通用字典的关联存储。换句话说,一个通用的 NSManagedObject 在不同的位置存储和访问值,并使用与其子类不同的设置和获取方法。在运行时,这可能会导致上下文混乱。

第一次检查上下文时,您会得到一个hasChangess==YES,因为您已将一个新对象插入到对象图中。第二次,您只是更改现有对象的属性。如果上下文不能准确地观察到name 键的值,它将不知道它必须在第二次传递时再次保存对象。

变化:

NSManagedObject *newManagedObject = [NSEntityDescription 
       insertNewObjectForEntityForName:[entity name]  inManagedObjectContext:context];

...到:

Friend *newFriend = [NSEntityDescription 
       insertNewObjectForEntityForName:[entity name]  inManagedObjectContext:context];

... 看看是否能解决问题。

否则,代码看起来不错。

【讨论】:

  • 谢谢!你可能是对的,观察我的朋友班的上下文肯定有问题(尽管它是第一次工作......)。不幸的是,您的更改建议并没有解决问题,但它仍然非常有帮助。如果我直接在 newManagedObject ([newManagedObject setValue:@"n2" forKey:@"name"] ) 上工作,一切正常。所以我认为我的 Friend-Class 或 xcdatamodel 一定有问题。我会深入挖掘一下,看看问题出在哪里。
【解决方案3】:

终于找到解决办法了!对于我上面的问题,我删除了所有不必要的代码(不幸的是我也删除了我的问题)。所以,完成这个线程:
我的Friend-class 也有成员:

@property (nonatomic) int duration;

在我的测试环境中,我还设置了duration(无论何时设置name)。 这似乎是上下文无法识别任何更改的原因。如果我将属性更改为

@property (nonatomic, retain) NSNumber duration;

一切正常。请注意,我的 xdatamodel 具有 duration 类型的属性 Int32。 我不明白的是,为什么第一个[context save]; 一切正常。但这对我来说现在还可以。

在这里给一些好的建议:

不要从你的 NSManagedObject 派生类生成你的 xdatemodel(就像我做的那样)。 而是创建您的 xdatemodel,然后从您的模型中生成您的类(Xcode->Design->DataModel->Copy Obj-C2.0..)!
03/2011 更新:从模型中生成类就像 XCode 4.0 中的魅力一样!)

我希望在这个美丽的星期天早上早点知道。
晚上好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-31
    相关资源
    最近更新 更多