Objective C 属性与 Core Data 的 ivar 问题
我花了几个小时试图解决这个问题,我认为这取决于我对 Objective C 的基本理解,尽管它是通过处理 Core Data 表现出来的。我并不感到惊讶——我使用 Objective C 和 Cocoa Touch 才两个月。
我的情况是,我有一系列模型,它们在 CD 中都连接良好。我的应用程序运行得很好,直到我昨天尝试扩展它。我的主模型作业位于视图控制器中,作为 .h 文件中的类属性。在我的 viewWillAppear 方法中,我必须通过另一个对象查找关系,所以我做了类似的事情:
/** project as an ivar **/
NSManagedObject *project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do something with divisions --> crash
...
/** project as a property **/
project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do someting, anything ---> A-OK!
那么,为什么当我尝试使用 [project valueForKey:] 的结果执行操作时,我的应用程序会崩溃,除非我创建项目阶级财产?
编辑
似乎只是在其中包含 if(!divisions)
条件(当视图首次加载时它应该为空),它不喜欢我上面提供的语句并生成 EXC_BAD_ACCESS
。但是,当忽略它时,我的代码工作正常。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(!divisions){
NSManagedObject *project = [[job valueForKey:@"project"] retain];
NSArray *divs = [[project valueForKey:@"divisions"] allObjects];
NSSortDescriptor *alphaSort = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
divisions = [[divs sortedArrayUsingDescriptors:[NSArray arrayWithObject:alphaSort]] mutableCopy];
}
[[self tableView] reloadData];
}
我承认存在更大的内存管理问题。我是否应该回去重新阅读一些关于 Obj-C 的书籍章节并回溯我的变量,以便它有意义?
I spent several hours trying to figure out this problem, and I think it comes down to my fundamental understanding of Objective C, though it manifested through working on Core Data. I'm not surprised - I've only been working with Objective C and Cocoa Touch for just two months now.
My situation is that I have a series of models that are all connected fine in the CD. My app works just fine until I tried extending it yesterday. I have my main model Job in a view controller as a class property in the .h file. In my viewWillAppear method I have to look up a relationship through another object, so I do something like:
/** project as an ivar **/
NSManagedObject *project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do something with divisions --> crash
...
/** project as a property **/
project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do someting, anything ---> A-OK!
So, why does my app crash when I try to do things with the results of [project valueForKey:] unless I make project a class property?
EDIT
It appears that simply including the if(!divisions)
conditional in there (which it should be null when the view first loads), it doesn't like the statements I provided above and produces the EXC_BAD_ACCESS
. However, when leaving it out, my code works fine.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(!divisions){
NSManagedObject *project = [[job valueForKey:@"project"] retain];
NSArray *divs = [[project valueForKey:@"divisions"] allObjects];
NSSortDescriptor *alphaSort = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
divisions = [[divs sortedArrayUsingDescriptors:[NSArray arrayWithObject:alphaSort]] mutableCopy];
}
[[self tableView] reloadData];
}
I'll accept that there's a bigger memory management problem going on. Should I probably go back and re-read some book chapters on Obj-C and retrace my variables so it makes sense?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据提供的有限代码,我无法确定,但崩溃的最简单解释是您不检查
divs
或divisions
数组是否为空在对它们执行任何操作之前。如果
Project.divisions
关系为空,则此:...将返回一个空数组。任何尝试寻址数组的任何元素(例如
[divs objectAtIndex:0]
)都会产生错误。此外,
divisions
似乎是控制器对象的 iVar,但您既不使用首选的self.divisions
引用形式,也不使用[divisions keep]< /code> 将 'divs' 数组分配给它时。由于
divs
数组将自动释放返回,因此当池下次耗尽时它将被清除,并且divisions
中的数组即使不为空也会消失。只需将
divisions
更改为self.divisions
即可修复。I can't tell for certain based on the limited code provided but the simplest explaination for the crash is that you don't check if the
divs
or thedivisions
arrays are empty before performing any operations on them.If the
Project.divisions
relationship is empty this:... will return an empty array. Any attempt to address any element of the array e.g.
[divs objectAtIndex:0]
will produce an error.Also,
divisions
appears to be an iVar of the controller object but you don't use either the preferredself.divisions
reference form nor a[divisions retain]
when assigning the 'divs' array to it. Since thedivs
array will be returned autoreleased, it will be purged when the pool next drains and the array indivisions
will disappear even if it is not empty.Simply change
divisions
toself.divisions
to fix.除了 ivar 混乱之外,您的代码还有两个其他问题。当访问 NSManagedObject 上的属性时,您应该使用 PrimitiveValueForKey: 就像在
任何时候您获取或设置现有托管对象的属性一样,您应该始终在调用之前使用 willAccessValueForKey: 并使用 didAccessValueForKey: 关闭,以便模型和存储保持不变同步。
更好的是
,但不幸的是 Xcode 调试器无法理解这一点,你必须忍受那些烦人的黄色警告。
此外, NSManagedObject 关系返回 NSSet 而不是数组:
请阅读 Apple 的 模型对象实现指南
最后,如果您执行所有这些操作来填充表,那么最好实例化一个 NSFetchedResultsController ,该控制器针对精确优化进行了优化那个任务。
Apart from the ivar confusion your code has two other problems. When accessing an attribute on an NSManagedObject you should use primitiveValueForKey: as in
Any time you get or set a property of an existing managed object, you should always precede the call with willAccessValueForKey: and close with didAccessValueForKey: so that the model and the store stay in sync.
Even better would be
but unfortunately the Xcode debugger doesn't grok that and you have to put up with those annoying yellow warnings.
Furthermore, an NSManagedObject relationship returns an NSSet not an array:
Read more in Apple's Model Object Implementation Guide
Lastly, if you're doing all this to populate a table, you're much better off instantiating an NSFetchedResultsController which is optimized for precisely that task.