NSManagedObject 子类导致 NSInvalidArgumentException
Posted
技术标签:
【中文标题】NSManagedObject 子类导致 NSInvalidArgumentException【英文标题】:NSManagedObject subclass causes NSInvalidArgumentException 【发布时间】:2011-04-05 20:24:16 【问题描述】:我正在尝试子类化我的 NSManagedObject 类来封装我的获取、设置、保存例程。该类使用它自己的 managedObjectContext 和一个共享的 persistentStoreCoordinator,因为这需要是线程安全的。
所有方法调用都没有问题,但是当我尝试执行 save: 方法时,我收到以下错误:
NSInvalidArgumentException', reason: '**-[MyEntity save:]: unrecognized selector sent to instance**'
附件是给出相同错误的简化版本。
这是子类的代码:
@interface XXMyEntity : MyEntity
@private
NSManagedObjectContext * _managedObjectContext;
- (XXMyEntity *) init;
- (BOOL) save:(NSError **)error;
- (NSManagedObjectContext *) managedObjectContext;
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator;
@end
@implementation XXMyEntity
- (XXMyEntity *) init
self = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
return self;
- (BOOL) save:(NSError **)error
return [[self managedObjectContext] save:error];
- (NSManagedObjectContext *)managedObjectContext
if (_managedObjectContext != nil)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator
newCoreDataAppDelegate * appDelegate = (newCoreDataAppDelegate *)[[UIApplication sharedApplication] delegate];
return appDelegate.persistentStoreCoordinator;
- (void) dealloc
[_managedObjectContext release];
[super dealloc];
@end
实现:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// Override point for customization after application launch.
XXMyEntity * myEntity = [[XXMyEntity alloc]init];
myEntity.id = [NSNumber numberWithInt:1];
myEntity.title = @"My Title";
[myEntity save:nil];
[self.window makeKeyAndVisible];
return YES;
我还尝试将方法签名更改为 saveEntity 之类的其他内容,假设我可能干扰了继承的方法但没有成功。
非常感谢任何帮助。
【问题讨论】:
你能像 foo 方法一样向 myEntity 发送测试消息吗? 看看有没有反应?我可以试试,但它确实响应 init 所以我认为那是一样的。 有趣的是,我添加了以下方法: - (void) something 它也抛出了错误。然而 init 确实有效。 我认为 init 有效,因为它直接传递给 MyEntity。你能用一些断点检查吗?而且你没有调用 super,初始化器看起来应该有点不同。 我解释了为什么它在我的答案中不起作用...self = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
不好 mmmmmmkay
【参考方案1】:
我认为您的主要问题是您的 init
方法要求对象已经具有托管对象上下文,即使您从未为其分配一个。当然,您不能为其分配一个,因为在init
self 之前不存在。有点悖论。正如乔指出的那样,无论如何您都在使用错误的实体。
您不应该以这种方式初始化托管对象子类。只需将它们插入到上下文中,就像您将通用托管对象一样,上下文将足够智能以返回正确的子类。如果要进行自定义,请在 awakeFromInsert
方法中进行。
【讨论】:
【参考方案2】:使用 init 函数的内存管理很差,就像在 init 之前调用 alloc 一样。此外,尽管您更改了 self 值,但它并没有使其成为 XXMyEntity
的类型,它仍然是 MyEntity
,这就是您收到错误的原因。
更新
要让 XXMyEntity 工作,您需要打开 xcdatamodel 文件并将 MyEntity 类设置为 XXMyEntity。还要通读 NSManagedObject 的Subclassing Notes。
【讨论】:
+1 这样的 init 函数通常注定要失败,尤其是在没有调用 super 的情况下。【参考方案3】:让我找出它的一些问题......
我假设 MyEntity 是 NSManagedObject 的子类。 XXXMyEntity 的意义何在?
- (NSManagedObjectContext *) managedObjectContext;
self = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
[b managedObjectContext]
将返回不同的上下文。这意味着可能无法正确获取对 b 的任何更改;很难说。
对+insertNewObjectForEntityForName:inManagedObjectContext:
的调用不会返回 XXXMyEntity 的实例(由 TechZen 标识)。
即使是这样,+insertNewObjectForEntityForName:inManagedObjectContext:
也会使用+alloc
和-init
构造托管对象。你已经覆盖了-init
,所以它会导致无限递归。
newCoreDataAppDelegate * appDelegate = (newCoreDataAppDelegate *)[[UIApplication sharedApplication] delegate]
;
-[UIApplication delegate]
可能很愚蠢。如果线程 是 主线程,那么您可能希望使用相同的 NSManagedObject 上下文。
如果您尝试使用 Core Data 在应用程序启动之间神奇地持久化内容,并且您在主线程上进行大部分处理,我有一些建议:
为整个应用分配一个 NSManagedObjectContext。您可能希望将其存储在应用委托或“单例”或其他内容中。使用“便利构造函数”而不是覆盖 -init:
+(MyEntity)实体 NSManagedObjectContext * 上下文 = ...; 我的实体 * 实体 = [NSEntityDescription 插入...]; 返回实体;
注意事项:
您仍然需要一种获取实体的方法(您可以使用更方便的构造函数来做到这一点) 您仍然需要删除对象以避免数据库变得庞大。 保存速度很慢。 如果您决定在后台线程中进行保存以免阻塞 UI,您需要仔细检查与 MyEntity 相关的每段代码,因为 NSManagedObject 和 NSManagedObjectContext 不是线程-安全。另请注意,在某些情况下,在同一个线程中有多个 MOC 是有意义的:如果您有一个带有取消按钮的“编辑”视图,您可以为编辑屏幕设置一个单独的 MOC,并且在用户取消时不保存.或者,我认为您可以使用单个 MOC 和 NSUndoManager。
Core Data Programming Guide: Technology Overview 给出了一个不错的列表,列出了核心数据是什么和不是什么;我怀疑你没有按预期使用它。
【讨论】:
以上是关于NSManagedObject 子类导致 NSInvalidArgumentException的主要内容,如果未能解决你的问题,请参考以下文章
当一对多相关的 NSManagedObject 子类发生更改时,如何更新 NSManagedObject 子类?