这是我第一次尝试使用ARC和Core Data。我似乎无法弄清楚为什么我的代码崩溃了。
在.h我有:
@interface Foo : NSObject {
}
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSString *email;
@property (nonatomic) BOOL myBool;
@property (nonatomic) float myFloat;
<。> <。>
@implementation User
@dynamic name;
@dynamic email;
@dynamic myBool;
@dynamic myFloat;
User *user = (User *)[NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:[appDelegate managedObjectContext]];
[user setName:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"name"]];
[user setEmail:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"email"]];
[user setAuthorisation_token:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"authentication_token"]];
[user setMyFloat:5]; <------ crash when set to anything other than 0 (eg,setting to FALSE will crash it).
[user setMyBool:FALSE]; <---- crash when set this to anything other than 0.
基本上每当我尝试使用字符串以外的类型时,我都会在该特定行上遇到EXEC崩溃。当我使用字符串时,一切都很好。在my.xcdatamodeld文件中,我将myFloat设置为FLOAT,将myBool设置为BOOLEAN
kill
error while killing target (killing anyway): warning: error on line 2184 of "/SourceCache/gdb/gdb-1708/src/gdb/macosx/macosx-nat-inferior.c" in function "void macosx_kill_inferior_safe()": (os/kern) failure (0x5x)
quit
Program ended with exit code: 0
答案 0 :(得分:6)
您不能将@dynamic用于基元(如float和BOOL),因为Core Data不会为它们创建实现。
因此,您的代码崩溃的原因是因为当您使用@dynamic
时,您告诉编译器“我保证这些getter和setter的实现将在运行时可用”。但由于Core Data没有创建它们,因此您的代码会尝试调用不存在的方法。
相反,你可以做两件事:对BOOL和浮点数使用NSNumber或者实现你自己的getter和setter。
使用NSNumber:
Core Data仅使用对象而不是基元,但您可以在Model中指定boolean或float。当你调用[user myFloat]
时,你实际上会得到一个带有浮点值的NSNumber。要访问原语,请调用float f = [[user myFloat] floatValue];
。布尔值也是如此,它也存储在NSNumber中。因此,当您尝试访问它时,您将获得一个NSNumber,您需要调用BOOL b = [[user isMyBool] boolValue];
来获取原语。
另一方面,在设置myFloat和myBool时,你需要将它们存储在NSNumber中,例如, [user setMyFloat:[NSNumber numberWithFloat:f]];
和[user setMyBool:[NSNumber numberWithBool:b]];
。
要使用此方法,您必须将最后两个属性更改为
@property (nonatomic, strong) NSNumber *myBool;
@property (nonatomic, strong) NSNubmer *myFloat;
但你可以保留@dynamic
。
实施自己的getter和setter:
为方便起见,您可能希望“user”对象直接获取和设置基本类型float和BOOL。在这种情况下,您应该将属性保持为float和bool,并在实现文件(.m)中删除myFloat和myBool的@dynamic
行。
要实现getter和setter,您需要了解一些关于KVC / KVO和Core Data的知识。简而言之:您需要告诉系统何时访问或更改属性以及何时完成访问或更改属性,因为Core Data不会为您执行此操作。在“将访问/更改”和“确实访问/更改”之间,您可以自由地检索或修改属性。还有一点需要注意的是,Core Data仍然无法直接保存BOOL和float,因此在获取和设置时需要将它们打包到NSNumbers中并从中解压缩。
此外,您无法调用[self setValue:ForKey:];
或[self valueForKey:@""];
,因为这会导致您所处的方法调用自身并使您陷入无限循环。 Core Data通过调用[self setPrimitiveValue:ForKey:]
和[self primiveValueForKey:]
来允许您获取和设置值而无需访问自己的实现,从而解决了这个用例。 注意: primiteValueForKey与原始类型(int,float,BOOL)无关,而只是您用于直接获取和设置Core Data中的值的方法的名称。
你的float和BOOL的实现看起来像这样:
- (float)myFloat
{
[self willAccessValueForKey:@"myFloat"];
float f = [[self primitiveValueForKey:@"myFloat"] floatValue];
[self didAccessValueForKey:@"myFloat"];
return f;
}
- (void)setMyFloat:(float)f
{
[self willChangeValueForKey:@"myFloat"];
[[self setPrimitiveValue:[NSNumber numberWithFloat:f] forKey:@"myFloat"];
[self didChangeValueForKey:@"myFloat"];
}
- (BOOL)isMyBool
{
[self willAccessValueForKey:@"myBool"];
BOOL b = [[self primitiveValueForKey:@"myBool"] boolValue];
[self didAccessValueForKey:@"myBool"];
return b;
}
- (void)setMyBool:(BOOL)b
{
[self willChangeValueForKey:@"myBool"];
[[self setPrimitiveValue:[NSNumber numberWithBool:b] forKey:@"myBool"];
[self didChangeValueForKey:@"myBool"];
}