iPhone核心数据崩溃与ARC

时间:2011-11-28 22:45:28

标签: iphone core-data ios4 ios5

这是我第一次尝试使用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

1 个答案:

答案 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"];
}
相关问题