核心数据的 Objective C 属性与 ivar 问题
Posted
技术标签:
【中文标题】核心数据的 Objective C 属性与 ivar 问题【英文标题】:Objective C property vs ivar issues with Core Data 【发布时间】:2011-04-30 17:52:59 【问题描述】:我花了几个小时试图解决这个问题,我认为这归结为我对 Objective C 的基本理解,尽管它通过对 Core Data 的工作表现出来。我并不感到惊讶 - 我使用 Objective C 和 Cocoa Touch 才两个月。
我的情况是我有一系列的模型在CD里都连接的很好。我的应用程序运行良好,直到我昨天尝试扩展它。我在视图控制器中有我的主要模型 Job 作为 .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 的书籍章节并追溯我的变量以使其有意义?
【问题讨论】:
只是猜测,但您是否在属性上设置了retain
?此外,如果您能够在崩溃时发布错误,这可能会对我们有所帮助!
第一种情况下的崩溃日志是怎么说的?
在第一种情况下,project 是一个局部变量,而不是 ivar。在第二种情况下,您将项目用作 ivar,而不是作为属性。您在这里有一些更大的内存管理问题,更多代码/上下文会有所帮助。
我不会怀疑我有一些内存管理问题 - 我来自 php、JS 类型的背景。我有点了解内存管理的想法,但我知道我真的不完全理解所有的来龙去脉。崩溃只是一个 EXC_BAD_ACCESS 并且在调试器中没有给出其他指示
这听起来肯定还有其他一些错误。您必须小心,不要专注于症状而错过根本原因。一方面,如果您使用@properties,内存管理(通常)会更容易,您在这里似乎没有这样做。 (不仅仅是声明,而是实际使用它们)。除此之外,您必须退后一步,不要看这几行代码,而是通常如何管理此 VC 和您的应用程序中的项目和部门对象。真正研究内存管理的每一小时都值得数百小时的调试。
【参考方案1】:
根据提供的有限代码,我无法确定,但对崩溃最简单的解释是,在对它们执行任何操作之前,您没有检查 divs
或 divisions
数组是否为空。
如果Project.divisions
关系为空,则:
NSArray *divs = [[project valueForKey:@"divisions"] allObjects];
... 将返回一个空数组。任何尝试解决数组的任何元素,例如[divs objectAtIndex:0]
会产生错误。
此外,divisions
似乎是控制器对象的 iVar,但在将“divs”数组分配给它时,您既没有使用首选的 self.divisions
引用形式,也没有使用 [divisions retain]
。由于divs
数组将自动释放返回,当池下一次耗尽时它将被清除,divisions
中的数组即使不为空也会消失。
只需将divisions
更改为self.divisions
即可修复。
【讨论】:
我没有意识到self.divisions
是必需的,因为只需输入 divisions
似乎就可以了。一般来说,这应该很容易修复,但在整个应用程序中需要做相当多的工作才能使其保持一致。不是不可能,只是可能有点乏味。感谢您的精彩提示!【参考方案2】:
除了 ivar 混乱之外,您的代码还有另外两个问题。访问 NSManagedObject 上的属性时,您应该使用primitiveValueForKey:如
[job willAccessValueForKey:@"project"];
NSManagedObject *project = [job primitiveValueForKey:@"project"];
[job didAccessValueForKey:@"project"];
无论何时获取或设置现有托管对象的属性,都应始终在调用之前使用 willAccessValueForKey: 并使用 didAccessValueForKey: 关闭,以便模型和存储保持同步。
会更好
[job willAccessValueForKey:@"project"];
NSManagedObject *project = [job primitiveProject];
[job didAccessValueForKey:@"project"];
但不幸的是,Xcode 调试器无法理解这一点,您必须忍受那些烦人的黄色警告。
此外,一个 NSManagedObject 关系返回一个 NSSet 而不是一个数组:
[project willAccessValueForKey:@"divisions"];
NSSet *divisions = [project primitiveValueForKey:@"divisions"];
[project didAccessValueForKey:@"divisions"];
在 Apple 的 Model Object Implementation Guide 中了解更多信息
最后,如果您正在执行所有这些操作来填充表格,那么最好实例化一个 NSFetchedResultsController,该控制器已针对该任务进行了优化。
【讨论】:
@Elise...也许阅读“陌生土地上的陌生人”会有助于“grok”的用法(咧嘴笑)。 链接错误和一个书呆子失礼?我应该待在床上。我会把它放在我的阅读清单上。顺便说一句,我认为这是 Hitchiker 的名言——如果没记错的话,是 Zaphod Beeblebrox。但话说回来,感叹的亚当斯先生是个博学的人。 -1 很抱歉降级,但在这种情况下,您绝对不想使用primativeValueForKey
。原始访问器几乎专门用于 NSManagedObject 子类中的自定义访问器或海量数据导入中。当您使用原始方法时,您会关闭 managedObjects 中的所有“管理”,这可能会导致您的对象图变得混乱。他也在 ios 上,不能使用数组控制器。
重读模型对象实施指南后,我相信您是对的。我一直在使用primitiveValueForKey: 没有问题的商店多年来没有改变,但如果模型确实包含错误,问题就会接踵而至。相应地修改我的答案。以上是关于核心数据的 Objective C 属性与 ivar 问题的主要内容,如果未能解决你的问题,请参考以下文章
Objective-C - 将类属性与 json 字典数据对齐
在 Objective-C 中按评论数量对核心数据中的 FetchedObjects 数组进行排序