Ios 将@dynamic与核心数据一起使用时发送到实例的选择器无法识别

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

我有一个NSManagedObject子类(SOCommand*),我正试图使用以下代码设置它的一个实例的属性:

    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]行。非常感谢!我以后一定会提到这一点。这篇文章的未来读者也将从中受益匪浅。