OS X Core Data Utility 教程崩溃

Posted

技术标签:

【中文标题】OS X Core Data Utility 教程崩溃【英文标题】:Crash in OS X Core Data Utility Tutorial 【发布时间】:2010-05-05 11:10:38 【问题描述】:

我正在尝试遵循 Apple 的核心数据实用程序教程。一切都很顺利,直到...

本教程使用 NSManagedObject 的自定义子类,称为“Run”。 Run.h 看起来像这样:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface Run : NSManagedObject 
    NSInteger processID;


@property (retain) NSDate *date;
@property (retain) NSDate *primitiveDate;
@property NSInteger processID;

@end 

现在,在 Run.m 中,我们有一个 processID 变量的访问器方法:

- (void)setProcessID:(int)newProcessID 
    [self willChangeValueForKey:@"processID"];
    processID = newProcessID;
    [self didChangeValueForKey:@"processID"];
  

在 main.m 中,我们使用函数来设置托管对象模型和上下文,实例化一个名为 run 的实体,并将其添加到上下文中。然后我们获取当前的NSprocessInfo,为设置run对象的processID做准备。

    NSManagedObjectContext *moc = managedObjectContext();

    NSEntityDescription *runEntity = [[mom entitiesByName] objectForKey:@"Run"];
    Run *run = [[Run alloc] initWithEntity:runEntity insertIntoManagedObjectContext:moc];

    NSProcessInfo *processInfo = [NSProcessInfo processInfo];

接下来,我们尝试调用Run.m中定义的访问器方法来设置processID的值:

[run setProcessID:[processInfo processIdentifier]];

这就是它崩溃的地方。对象 run 似乎存在(我可以在调试器中看到它),所以我不认为我在传递 nil;另一方面,它看起来不像 setProcessID: 消息实际上正在被接收。我显然还在学习这些东西(这就是教程的用途,对吧?),而且我可能正在做一些非常愚蠢的事情。但是,我们将不胜感激地收到任何帮助或建议!

===更多信息===

跟进 Jeremy 的建议:

模型中的processID属性是这样设置的:

NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc]init];
    [idAttribute setName:@"processID"];
    [idAttribute setAttributeType:NSInteger32AttributeType];
    [idAttribute setOptional:NO];
    [idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];

这似乎有点奇怪;我们将它定义为一个标量类型,然后给它一个 NSNumber 对象作为它的默认值。在关联的类 Run 中,processID 被定义为一个 NSInteger。不过,这应该没问题 - 都是直接从教程中复制的。

在我看来,问题可能出在某个地方。顺便说一下,processID 的 getter 方法是这样定义的:

- (int)processID 
    [self willAccessValueForKey:@"processID"];
    NSInteger pid = processID;
    [self didAccessValueForKey:@"processID"];
    return pid;

而且这种方法效果很好;它访问并解压缩 processID (-1) 的默认 int 值。

感谢到目前为止的帮助!

【问题讨论】:

当你说它崩溃时,你得到什么崩溃?它是某种 Objective-C 异常吗?访问不正确?我们需要更多信息。 对不起;这是一个错误的访问:程序接收到的信号:“EXC_BAD_ACCESS”。 【参考方案1】:

如果你得到 EXC_BAD_ACCESS

[run setProcessID:[processInfo processIdentifier]];

几乎可以肯定是因为其中一个指针不再指向真实对象。 run 已被解除分配或 processInfo 已被解除分配。这假设该行不是之后的下一行代码

NSProcessInfo *processInfo = [NSProcessInfo processInfo];

如果是,那么这两个对象都应该是有效的,所以你可能正在寻找一些错误

[self willChangeValueForKey:@"processID"];

[self didChangeValueForKey:@"processID"];

如果您有任何对象观察到该键,则它们可能已经过时了。

【讨论】:

谢谢,杰里米。我怀疑这些指针是有效的,因为(a)我现在尝试在启用僵尸的情况下运行,并且我得到了同样的崩溃,并且(b)另外,我尝试将 [processInfo processIdentifier] 的结果存储到一个 int变量(有效),然后使用该变量作为 setProcessID 的参数: - 就像以前一样崩溃。事实上,仅仅执行 [run setProcessID:1] 也会崩溃。所以,它看起来像是第二种可能性——KVO 问题。我没有设置任何对象来观察 processID,但大概是 Core Data 中的某些东西(上下文?)观察键? processID 是数据模型中定义的属性吗?如果是,它可能应该是一个 NSNumber。 事实上,为了让 KVC 工作,属性可能需要是一个对象。 valueForKEy:返回一个 id。 这个问题的一个常见原因是没有在数据模型中设置正确的托管对象类。如果你有一个自定义类,但在数据模型中有默认类,你就会遇到这种麻烦。 TechZen - 就是这样!我错过了关键的一行:[runEntity setManagedObjectClassName:@"Run"]; - 它现在可以工作了!非常感谢所有为我看过这个的人。【参考方案2】:

这并没有解决我的 willAccessValueForKey 问题,但它解决了一个谜。我对实体进行了子类化,但忘记在模型中设置自定义类。自定义类一直有效,直到我编写了一个方法来发送回一个字符串,该字符串是一些属性的串联。该方法与另一个自定义 NSManagedObject 类中的另一个方法几乎相同。我不明白为什么一个班有效而另一个班没有。一旦我在模型中设置了自定义类,它们都可以工作。

【讨论】:

以上是关于OS X Core Data Utility 教程崩溃的主要内容,如果未能解决你的问题,请参考以下文章

OS X Core Data - 将托管对象上下文传递给视图控制器

Core Data Macos 应用程序和与 OS X 10.7 的兼容性

为啥 Core Data SQLite 存储不能从 OS X 10.8 向后兼容到 10.4?

Core Data Mac OS X 基于文档的应用程序中的 NSArrayController 类与实体模式

在重新加载文档之前,如何在 OS X 上的 iCloud 中检测对 Core Data 文档的更改?

在 Mac OS X 和 iOS 的 Core Data 中存储贝塞尔路径