EXC_BAD_ACCESS设置Core Data实体属性

时间:2014-03-24 21:48:29

标签: objective-c core-data

我已经看到人们在Core Data模型中使用整数类型的一些问题,但后来尝试在代码中使用整数而不设置复选框以使用标量。但是,我实际上是这样做的。

  1. 在实体上创建Integer 64属性
  2. 从该实体创建NSManagedObject子类
  3. 选中“使用基本数据类型的标量属性”框。
  4. 这会产生:

    @interface State : NSManagedObject @property (nonatomic) int64_t serverId; @end

    但是,然后,在运行时,我将使用以下代码获得EXC_BAD_ACCESS错误:

    int64_t someValue = 313; State *state = ... // standard [NSEntityDescription insert code state.serverId = someValue;

    其中'state'是NSManagedObject子类,serverId是Integer 64属性。 但是,以下代码有效:

    state.serverId = [NSNumber numberFromInt:someValue];

    但是,由于serverId实际上被声明为int64_t,因此会产生警告。并且,实际上尝试访问该值会产生可能是指针地址的内容(尽管%@看起来像我期望的那样)。

    所以,我想我的问题是,Core Data中的哪些内容已经被我的int64_t作为NSNumber了?查看Model和NSAttributeDescription,它是一个NSInteger64AttributeType。

    我认为可能与此有关的事情:

    • 忘记检查复选框,然后重新生成课程
    • 更新架构并迁移

    在第一个例子中,这似乎是一个常见的情况,我已经尝试过了,并且,正如预期的那样,我无法重现我的问题。对于第二种情况,我删除了我的模型文件并重新创建了所有内容,删除了我的DerivedData目录。

1 个答案:

答案 0 :(得分:0)

如果您计划同时支持32位广告64位架构,则需要远离形式标量。

首先阅读CocoaTouch 64 Bit Guide

在您的代码中,请注意intNSInteger

model使用Integer32Integer64。位大小取决于应用程序对数字空间的要求。如果你的服务器ID都在313左右,你应该可以使用32位,如果你有真正的大数字与integer64一起使用。

我知道你目前使用的是integer64。为了避免迁移的需要,现在只需坚持使用integer64。但是也要测试你的应用程序的32位架构。

在实体类中使用NSNumber,不要对存储中存储的属性使用标量。

@interface State : NSManagedObject
   @property (nonatomic, retain) NSNumber *serverId; 
@end

@implementation State
   @dynamic serverId;  // this will create the default accessor for you
@end

CoreData将完成从Integer32或Integer64转换为NSNumber的魔力,您无需担心转换警告。

在您的应用代码中使用numberFromInteger而不是numberFromInt

 state.serverId = [NSNumber numberFromInteger:someValue];

自定义访问者为整数

如果您有很多NSIntegers,并且想要编写类似

的内容
 NSInteger someInteger;
 state.serverIdInteger =  someInteger;
 // or
 someInteger = state.serverIdInteger;

然后您将需要serverID的自定义访问者。您的模型不会更改,更改是实体类。

@interface State : NSManagedObject
   @property (nonatomic, retain) NSNumber *serverId; 
   @property (nonatomic) NSInteger serverIdInteger; //custom accessor
@end

@implementation State
@dynamic serverId;  // this will create the default *serverId* accessor 

// now do custom accessor
-(void)setServerIdInteger:(NSInteger)anInteger {
   [self willChangeValueForKey:@"serverId"];
   [self setServerId:[NSNumber numberWithInteger:anInteger]];
   [self didChangeValueForKey:@"serverId"];
}

-(NSInteger)serverIdInteger {
    [self willAccessValueForKey:@"serverId"];
    NSNumber *tmpValue = [self serverId];
    [self didAccessValueForKey:@"serverId"];
    return (tmpValue!=nil) ? [tmpValue integerValue] : 0;
}

@end