EXC_BAD_ACCESS 设置核心数据实体属性

Posted

技术标签:

【中文标题】EXC_BAD_ACCESS 设置核心数据实体属性【英文标题】:EXC_BAD_ACCESS on setting Core Data entity property 【发布时间】:2014-03-24 21:48:29 【问题描述】:

我发现人们在 Core Data 模型中使用整数类型存在一些问题,但随后尝试在代码中使用整数而不将复选框设置为使用标量。但是,我实际上正在这样做。

    在实体上创建一个整数 64 属性 从该实体创建一个 NSManagedObject 子类 选中“对原始数据类型使用标量属性”框。

这会生成:

@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 上?查看模型和 NSAttributeDescription,它是一个 NSInteger64AttributeType。

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

忘记选中该框并重新生成类 更新架构并迁移

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

【问题讨论】:

【参考方案1】:

如果您计划同时支持 32 位和 64 位架构,您将希望远离标量。

首先阅读CocoaTouch 64 Bit Guide

在你的代码中注意intNSInteger

model 中使用Integer32Integer64。位大小取决于应用程序对数字空间的要求。如果您的 serverID 都在 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

【讨论】:

一个 int64_t 在任何平台上都是 64 位的。这就是 64 位 int 的定义。

以上是关于EXC_BAD_ACCESS 设置核心数据实体属性的主要内容,如果未能解决你的问题,请参考以下文章

核心数据:EXC_BAD_ACCESS 访问关系

核心数据 - 访问从 fetch EXC_BAD_ACCESS 返回的对象

非零整数值的核心数据 EXC_BAD_ACCESS

核心数据不保存一个实体的属性

创建了核心数据实体但未保存属性

核心数据模型设置