Ios 将@dynamic与核心数据一起使用时发送到实例的选择器无法识别
我有一个NSManagedObject子类(SOCommand*),我正试图使用以下代码设置它的一个实例的属性:Ios 将@dynamic与核心数据一起使用时发送到实例的选择器无法识别,ios,objective-c,core-data,Ios,Objective C,Core Data,我有一个NSManagedObject子类(SOCommand*),我正试图使用以下代码设置它的一个实例的属性: SOCommand* newCommand = [[SOCommand alloc]init]; newCommand.commandName = self.tf_commandName.text; newCommand.sshCommand = self.tf_sshCommand.text; 但是,我得到了一个错误: *** Terminating ap
SOCommand* newCommand = [[SOCommand alloc]init];
newCommand.commandName = self.tf_commandName.text;
newCommand.sshCommand = self.tf_sshCommand.text;
但是,我得到了一个错误:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SOCommand setCommandName:]: unrecognized selector sent to instance
我认为将预先编写的@dynamic
更改为@synthesis
可以解决这个问题。虽然它确实解决了这个错误,但它导致了其他错误,因为核心数据需要@dynamic
。我应该如何设置它的属性?我在某个地方读到,您必须以一种特殊的方式初始化NSManagedObjects
,但这涉及到“添加”到数据库,所以我真的很困惑
谢谢
~rutterfizz您应该使用以下方法插入新的CoreData对象:
[NSEntityDescription insertNewObjectForEntityForName:@"SOCommand" inManagedObjectContext:self.managedObjectContext];
您初始化SOCommand的方式会导致此错误。您没有显示足够的代码来验证此错误,但我怀疑您犯了几个常见错误之一 常见问题#1:未正确设置托管对象模型 我无法在代码中演示这一点,但托管对象模型必须包含所需的每个属性。仅在对象子类中添加新的
@property
声明不会将其添加到模型中。这两个地方都必须存在
常见问题2:实现Getter/Setter并调用Super
- (void)setCommandName:(NSString *)commandName
{
// Do "willUpdateCommandName" logic here
//Call Super
[super setCommandName:commandName];
// Do "didUpdateCommandName" logic here
}
在CoreData之外,这是一个相当常见的构造,但在CoreData内部,这是一个常见的问题。相反,您应该调用原语setter
- (void)setCommandName:(NSString *)commandName
{
// Do "willUpdateCommandName" logic here
//Call Super
[self setPrimitiveCommandName:commandName];
// Do "didUpdateCommandName" logic here
}
常见问题3:您正在使用-init
初始化对象,而不是-initWithEntity:insertIntoManagedObjectContext:
您在代码示例中肯定犯了这个错误,但其他人也可能犯了这个错误,您不应该使用-init
。在内部,我怀疑它需要NSEntityDescription来动态生成对象的getter/setter
如果不希望立即插入对象,可以将nil
作为NSManagedObjectContext
传递,但必须传递从NSManagedObjectModel
获取的NSEntityDescription
。正确地这样做看起来像这样
// Macro for easy reading/writing
#define SOClass(x) NSStringFromClass([x class])
// It is important to note that the entity name *CAN* be different from the class name, but generally it is not
NSString *entityName = SOClass(SOCommand);
NSDictionary *entities = self.managedObjectModel.entitiesByName;
NSEntityDescription *entityDescription = entities[entityName];
SOCommand *newCommand = [[SOCommand alloc] initWithEntity:entityDescription
insertIntoManagedObjectContext:nil];
如果您知道要使用的上下文,也可以使用以下语法:
// Macro for easy reading/writing
#define SOClass(x) NSStringFromClass([x class])
// It is important to note that the entity name *CAN* be different from the class name, but generally it is not
NSString *entityName = SOClass(SOCommand);
SOCommand *newCommand = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.managedObjectContext];
同意@johnMa,这是创建/插入新核心数据对象的正确方法,每次都必须这样做。即创建并初始化对象,然后需要设置其属性。因此,上面的这行替换了您的[[alloc]init]行。非常感谢!我以后一定会提到这一点。这篇文章的未来读者也将从中受益匪浅。