CoreData:第一次加载 NSManagedObject 时未访问自定义属性访问器

Posted

技术标签:

【中文标题】CoreData:第一次加载 NSManagedObject 时未访问自定义属性访问器【英文标题】:CoreData: Custom attribute accessor not accessed the first time NSManagedObject is loaded 【发布时间】:2012-10-07 17:08:26 【问题描述】:

最终目标:我有一个由叶子组成的对象图,连接到其他叶子。我需要遍历对象图并返回所有未枯萎的叶子,并且 1)没有子叶子或 2)所有子叶子都枯萎了。

情况:我有一个 NSFetchedResultsController 和表格视图,我想在其中显示结果。

我的尝试: 我开始尝试在 NSFetchRequest 上使用 NSPredicate,但意识到我无法看到哪个可以递归地遍历叶子的子叶子及其所有子叶子等...

所以我向 Leaf 对象添加了一个名为“isFarthestNonWiltedLeaf”的属性,并在 Leaf 上的一个类别中创建了一个自定义 get-accessor:

- (NSNumber*) isFarthestNonWiltedLeaf

    [self willAccessValueForKey:@"isFarthestNonWiltedLeaf"];
    NSNumber *returnValue = @([self.wilted boolValue] == NO && [[self allSubLeavesAreWilted] boolValue]);
    [self didAccessValueForKey:@"isFarthestNonWiltedLeaf"];

    return returnValue;


- (NSNumber*) allSubLeavesAreWilted

    for(Leaf *aLeaf in self.subLeaves)
    
        if([aLeaf.wilted boolValue] == NO || ![[aLeaf allSubLeavesAreWilted] boolValue])
            return @NO;
    
    return @YES;

然后,在 NSFetchedResultsController 的 fetch 请求上,我设置了以下谓词:

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isFarthestNonWiltedLeaf == YES"]];

这在我第一次打开应用程序并开始在不同的视图中添加叶子和子叶子时效果很好。但是,下次我打开应用程序时,自定义访问器方法在第一次出现表格视图时没有访问!我必须去每个叶子并检查/取消选中它的“枯萎”状态,然后让 NSFetchedResultsController 刷新那个单一的叶子......此时它确实调用了自定义 isFarthestNonWiltedLeaf 访问器并且叶子正确地出现在列表中。我必须为每个叶子执行此操作才能正确更新整个 tableview。

所以我的问题是……如何让 NSFetchRequest / NSFetchedResultsController 每次都使用 Leaf 对象的自定义 get 访问器?谢谢。

【问题讨论】:

【参考方案1】:

好吧,我将不得不回答我自己的问题......我玩了更多,我发现了这个问题,但我仍然不确定它的“原因”。

我意识到 CoreData 中有很多缓存正在进行,所以即使我在 NSFetchedResultsController 上将 cacheName 设置为 nil,我还是觉得那里有一些问题。此外,似乎在没有调用 get 访问器的情况下访问了原始属性。

换句话说,原语需要被保存。所以我在计算值之后在get访问器中添加了以下几行:

[self setPrimitiveValue:returnValue forKey:@"isFarthestNonWiltedLeaf"];

起初我还添加了 KVO 通知代码(willChangeValueForKey 和 didChangeValueForKey),但由于某种原因,这使得应用程序完全没有响应......这似乎是一些循环引用问题。

所以最终的代码如下所示:

- (NSNumber*) isFarthestNonWiltedLeaf

    [self willAccessValueForKey:@"isFarthestNonWiltedLeaf"];
    NSNumber *returnValue = @([self.wilted boolValue] == NO && [[self allSubLeavesAreWilted] boolValue]);
    [self didAccessValueForKey:@"isFarthestNonWiltedLeaf"];

    [self setPrimitiveValue:returnValue forKey:@"isFarthestNonWiltedLeaf"];

    return returnValue;


- (NSNumber*) allSubLeavesAreWilted

    for(Leaf *aLeaf in self.subLeaves)
    
        if([aLeaf.wilted boolValue] == NO || ![[aLeaf allSubLeavesAreWilted] boolValue])
            return @NO;
    
    return @YES;

...使用 NSPredicate 如下:

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isFarthestNonWiltedLeaf == YES"]];

【讨论】:

以上是关于CoreData:第一次加载 NSManagedObject 时未访问自定义属性访问器的主要内容,如果未能解决你的问题,请参考以下文章

CoreData:第一次加载 NSManagedObject 时未访问自定义属性访问器

Core Data 获取关系对象

CoreData fetch() 返回无序对象

CoreData 和大表

Core Data 使用多个上下文中的新对象从后台线程订购一对多关系保存

UNIQUE 约束失败:ZTEMPORADA.Z_PK