为什么未建模的财产解雇了这个错误?

时间:2013-05-06 03:09:24

标签: ios objective-c core-data

我们知道NSFetchRequest的propertiesToFetch可以限制我们想要的属性,它可以减少内存的占用空间。 如果我们这样做:

request.propertiesToFetch = [NSArray arrayWithObjects:@"nID", nil];

    NSString *strID = [NSString stringWithFormat:@"%@", aPerson.nID];
cell.textLabel.text = strID;

然后调试输出(而不是触发故障):

CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.ZNID FROM ZPERSON t0 ORDER BY t0.ZNID

然而,当我向NSManagedObject Person的子类添加一个新的未建模属性时,发生了一件奇怪的事情。 就像这样:

@interface Person (Ex)
@property (nonatomic, retain) NSString *strTempName;
@end

@implementation Person (Ex)
@dynamic strTempName;

-(void)setStrTempName:(NSString *)strTempName
{
    [self setPrimitiveValue:strTempName forKey:@"strTempName"];
}

-(NSString*)strTempName
{
    return [self primitiveValueForKey:@"strTempName"];
}

这是访问新的未建模属性的地方:

NSString *strTT = aPerson.strTempName;

然后调试输出:

2013-05-06 10:43:07.789 TestCoreData[988:c07] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZBISFORTEST, t0.ZBISINTRASH, t0.ZNID, t0.ZSTRNAME, t0.ZSTROK, t0.ZSTROK2, t0.ZSTRTEST1, t0.ZSTRTEST2, t0.ZADEPART, t0.ZAMIDDLETHUMNAIL, t0.ZANORMALPIC, t0.ZASMALLTHUMNAIL FROM ZPERSON t0 WHERE  t0.Z_PK = ? 
2013-05-06 10:43:07.790 TestCoreData[988:c07] CoreData: annotation: sql connection fetch time: 0.0010s
2013-05-06 10:43:07.791 TestCoreData[988:c07] CoreData: annotation: total fetch execution time: 0.0018s for 1 rows.
2013-05-06 10:43:07.792 TestCoreData[988:c07] CoreData: annotation: fault fulfilled from database for : 0x898a030 <x-coredata://CAD35D43-F6B2-4463-B59B-C9A3CD488935/Person/p51846>

从上面的输出消息中,我们可以找到unmodeled属性而不是SELECT t0.Z_ENT,t0.Z_PK,t0.ZNID,SELECT生成所有属性句子并触发故障!

但是,我已经阅读了一些有关未建模属性(here is link)的消息:

  

因为未建模的属性只是自定义的属性   NSManagedObject子类而不是实体,故障对象知道   他们没什么。故障对象从数据模型初始化   这样他们响应的所有密钥都必须在数据模型中。这个   意味着故障不能可靠地响应未建模的请求   属性。

为什么奇怪的事情会发生?

提前感谢。


@Anonymous,

选择1): 应用程序崩溃,调试输出显示:

2013-05-06 14:03:05.665 TestCoreData[1794:c07] -[Person strTempName]: unrecognized selector sent to instance 0x6ba77b0
2013-05-06 14:03:30.395 TestCoreData[1794:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person strTempName]: unrecognized selector sent to instance 0x6ba77b0'

选择2): 首先,像willAccessValueForKey等方法是发送KVO更改通知,就像NSManagedObject.h中的注释一样:

- (void)willAccessValueForKey:(NSString *)key;      // read notification
- (void)didAccessValueForKey:(NSString *)key;       // read notification (together with willAccessValueForKey used to maintain inverse relationships, to fire faults, etc.) 

其次,在选择2)代码后,我的应用程序中仍然存在奇怪的事情(触发故障)。

也感谢你的回复。

3 个答案:

答案 0 :(得分:0)

出现问题:

第一:这是正确的,@动态是错误的。访问者在您的代码中。没有任何动态。

第二:原始访问器用于建模属性。你有一个“伊塔尔财产”。只需按照在其他任何地方使用它的方式使用它。 (但是添加... access ...和...... change ......方法。)

更改后,重新检查是否触发故障。

+++ 在-didAccessValueForKey :( NSManagedObject)的文档中,您将找到正确实现的示例:

- (NSString *)firstName
{
    [self willAccessValueForKey:@"firstName"];
    NSString *rtn = firstName;
    [self didAccessValueForKey:@"firstName"];
    return rtn;
}

答案 1 :(得分:0)

return [self primitiveValueForKey:@"strTempName"];

这是错误的。 primitiveValueForKey用于访问建模属性。由于你的属性没有建模,你得到了所有奇怪的行为 - 核心数据触发错误,因为它正在寻找属性,当它找不到它时,它会引发异常。

你想要达到什么目的?也许你正在寻找一个瞬态属性,或者你应该像在任何其他对象中一样合成属性?

答案 2 :(得分:-1)

我认为你的编码太多了。 @dynamic为您生成getter和setter。你有两个选择。

1)删除setter / getter调用。

2)修改你的getter / setter以警告系统你正在改变值:

-(void)setStrTempName:(NSString *)strTempName
{
    [self willChangeValueForKey:@"strTempName"];
    [self setPrimitiveValue:strTempName forKey:@"strTempName"];
    [self didChangeValueForKey:@"strTempName"];
}

-(NSString*)strTempName
{
    [self willAccessValueForKey:@"strTempName"];
    NSString *tmp = [self primitiveValueForKey:@"strTempName"];
    [self didAccessValueForKey:@"strTempName"];
    return tmp;
}