在Marcus Zarra的核心数据手册的第40页中,他建议,由于NSTreeController需要相同的密钥来访问层次结构中的所有对象(例如,子级),这可能意味着关系名称不太有意义,您可以编写额外的适合所需关系的访问者。我认为这是一个好主意,但我不确定如何实现它。
让我以Aperture的数据模型为例:您可以拥有多个库,每个库都可以有很多项目,每个库都可以有很多照片。所以,如果我将我的实体命名为图书馆,项目,图片及其关系项目,照片并且没有分别是以下适当的库实现?
Library.h
@interface Library: NSManagedObject {
}
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSSet *projects;
@property (nonatomic, retain) NSSet *children;
@property (nonatomic, retain) id parent;
@end
@interface Library (CoreDataGeneratedAccessors)
- (void)addProjectsObject:(Project *)value;
- (void)removeProjectsObject:(Project *)value;
- (void)addProjects:(NSSet *)value;
- (void)removeProjects:(NSSet *)value;
- (id)parent;
- (void)setParent;
@end
和Library.m
#include "Library.h"
@implementation Library
@dynamic title;
@dynamic projects;
- (NSSet*) children {
[self willAccessValueForKey:@"children"];
NSSet *set = [self valueForKey:@"projects"];
[self didAccessValueForKey:@"children"];
return set;
}
- (void) setChildren:(NSSet*)children {
[self willChangeValueForKey:@"children"];
[self setValue:children forKey:@"projects"];
[self didChangeValueForKey:@"children"];
}
- (id)parent {
[self willAccessValueForKey:@"parent"];
[self didAccessValueForKey:@"parent"];
return nil;
}
- (void)setParent:(id)parent {
// Proposed parent value is ignored. Libraries have no parent.
[self willChangeValueForKey:@"parent"];
[self didChangeValueForKey:@"parent"];
}
@end
子元素和父元素应该是头文件中的属性吗?
这是建议的实施吗?我还应该加入addChildrenObject:
,removeChildrenObject:
,addChildren:
和removeChildren:
吗?并实施它们? (父方法也是如此。)
我假设Core Data模型中根本没有出现儿童。是对的吗?那么反推的关系如何推断呢?
我应该在setChildren中调用[self willChangeValueForKey:@“children”]:所以孩子们是否符合KVO标准? (与其他访问者相同。)
在第41页中,M。Zarra建议实施NSOutlineDataSource而不是使用NSTreeController,因为“结果可能是意外且不清楚”。有谁知道这些限制是什么?
最后,如果我实现NSOutlineDataSource,你会建议缓存根对象的获取吗?如果是这样,维护此缓存数组与Core Data同步的正确方法是什么?
谢谢。
致以最诚挚的问候,
豪尔赫
答案 0 :(得分:1)
我认为当前版本的NSTreeController不需要实际命名为“children”和“parent”的属性。您可以使用setChildrenKeyPath:
将子路径设置为任何属性名称(只要该属性实现父子层次结构。)我很确定这是一个相当古老的要求。 (带上一粒盐,我有时没用树控制器。见下文)
至于你的其他问题:
(1)是
(2)是,是和是
(3)关系保持在真实属性中,例如属性。实体/对象图与父子属性虚拟化的虚拟图分开。由于父元素和子元素实际上没有值,因此实际值的任何更改都会立即反映在它们的返回值中,反之亦然。简而言之,您不必担心它们。
(4)是的,树控制器将观察虚拟属性而不是真实属性。如果虚拟属性不符合KVO,则控制器将无法工作。
(5)历史上,NSTreeController被认为是错误的。它自2004年IIRC以来一直存在,它从未真正起作用。许多旧手完全忽略它。我有一段时间没用过它。
(6)您通常只缓存预计不会发生太大变化的数据。如果获取用于实际更新模型或预期其他东西更新模型,例如一个URL请求,那么你不应该使用缓存。
答案 1 :(得分:1)
我在这里看到的问题是,虽然设置“children”属性会触发“projects”属性的KVO,反之则不然。因此,如果通过“项目”关系将项目添加到库对象,则大纲视图将不会更新,因为它不会在“children”属性中看到任何更改。
启用此功能的最简单方法是实现如下方法:
+ (NSSet*)keyPathsForValuesAffectingChildren
{
return [NSSet setWithObject:@"projects"];
}
那应该对“projects”属性进行任何更改也会触发“孩子”的KVO通知。
另一方面,由于“children”属性不属于您的Core Data模型,我认为will/didAccessValueForKey:
调用不是必需的,尽管我认为它们不会受到伤害任何东西。此外,如果您实现上面提到的方法,则不再需要在will/didChangeValueForKey:
方法中调用setChildren:
,因为当“项目”键更改时,Cocoa应自动触发KVO。