NSOutlineView、NSTreeController 和异构层次结构

发布于 2024-09-06 04:39:30 字数 2279 浏览 4 评论 0原文

在 Marcus Zarra 的《核心数据》一书中的第 40 页中,他建议,由于 NSTreeController 需要相同的密钥来访问层次结构中的所有对象(例如子对象),并且这可能意味着意义不大的关系名称,因此您可以为期望的关系。我认为这是一个好主意,但我不确定如何实施。

让我以Aperture的数据模型为例:你可以有很多库,每个库可以有很多项目,每个库可以有很多照片。因此,如果我将我的实体命名为Library项目照片及其关系项目照片 分别是什么,以下是库的正确实现吗?

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
  1. children和parent应该是头文件中的属性吗?

  2. 这是建议的实施吗?我还应该包含 addChildrenObject:removeChildrenObject:addChildren:removeChildren: 吗?并实施它们? (父方法也是如此。)

  3. 我假设子方法根本不会出现在核心数据模型中。是这样吗?那么反向关系是如何推断出来的呢?

  4. 我应该在setChildren中调用[self willChangeValueForKey:@"children"]:这样children就符合KVO吗? (其他访问器也是如此。)

  5. 在第 41 页中,M. Zarra 建议实现 NSOutlineDataSource 而不是使用 NSTreeController,因为“结果可能是意外且不清楚的”。有谁知道这些限制是什么?

  6. 最后,如果我实现 NSOutlineDataSource,您会建议缓存根对象的获取吗?如果是这样,保持此缓存数组与核心数据同步的正确方法是什么?

谢谢。

最好的问候,

豪尔赫

In page 40 of Marcus Zarra's Core Data book, he suggests that, since NSTreeController requires the same key for accessing all the objects in the hierarchy (for example, children) and that could imply less meaningful relationship names, you can write additional accessors for the desired relationships. I think that this is a great idea, but I am not sure of how to implement it.

Let me use Aperture’s data model as an example: You can have many libraries, each one of them can have many projects, and each of them can have many photos. So, if I name my Entities Library, Project, and Photo and their relationships projects, photos and nothing respectively, is the following a proper implementation for Library?

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

and 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
  1. Should children and parent be properties in the header file?

  2. Is this the suggested implementation? Should I also include addChildrenObject:, removeChildrenObject: , addChildren:, and removeChildren:? And implement them? (Same goes for the parent methods.)

  3. I assume that children doesn’t appear at all in the Core Data model. Is that right? How are the reverse relationships inferred then?

  4. Should I call [self willChangeValueForKey:@"children"] in setChildren: so children is KVO compliant? (Same for the other accessors.)

  5. In page 41 M. Zarra recommends to implement NSOutlineDataSource instead of using NSTreeController due to “results [that] can be unexpected and unclear”. Does anyone know what are those limitations?

  6. Finally, if I implement NSOutlineDataSource, would you recommend caching the fetch for the root objects? And if so, what is the proper way to maintain this cached array in sync with Core Data?

Thank you.

Best regards,

Jorge

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

飘落散花 2024-09-13 04:39:30

我在这里看到的问题是,虽然设置“children”属性将触发“projects”属性的 KVO,但反之则不然。因此,如果您通过“项目”关系将项目添加到库对象,大纲视图将不会更新,因为它不会看到“子项”属性中的任何更改。

启用此功能的最简单方法是实现如下方法:

+ (NSSet*)keyPathsForValuesAffectingChildren
{
    return [NSSet setWithObject:@"projects"];
}

对“projects”属性的任何更改也会触发“children”的 KVO 通知。

顺便说一句,由于“children”属性不是核心数据模型的一部分,我认为 will/didAccessValueForKey: 调用不是绝对必要的,尽管我不认为它们会伤害任何东西。另外,如果你实现了我上面提到的方法,你应该不再需要在 setChildren: 方法中调用 will/didChangeValueForKey: ,因为 Cocoa 应该自动触发 KVO当“projects”键改变时。

The problem I see here is that, while setting the "children" property will trigger KVO for the "projects" property, the reverse is not true. So, if you add a project to the library object via the "projects" relationship, the outline view will not update because it will not see any change in the "children" property.

The easiest way to enable this is to implement a method like so:

+ (NSSet*)keyPathsForValuesAffectingChildren
{
    return [NSSet setWithObject:@"projects"];
}

That should make any changes to the "projects" property also trigger a KVO notification for "children" as well.

On a side note, since the "children" property isn't part of your Core Data model, I don't think the will/didAccessValueForKey: calls are strictly necessary, though I don't think they'll hurt anything. Also, if you implement the method I mentioned above, you should no longer need to call will/didChangeValueForKey: in the setChildren: method, as Cocoa should automatically trigger the KVO for that when the "projects" key is changed.

笛声青案梦长安 2024-09-13 04:39:30

我认为当前版本的 NSTreeController 不需要实际上名为“children”和“parent”的属性。您可以使用 setChildrenKeyPath: 将子路径设置为任何属性名称(只要该属性实现父子层次结构)。我很确定这是一个相当古老的要求。 (持保留态度,我有一段时间没有使用树控制器。见下文)

至于你的其他问题:

(1)是

(2)是,是和是

(3)关系维护在真正的属性,例如财产。实体/对象图与父子属性虚拟化的虚拟图是分开的。由于父属性和子属性实际上没有值,因此实际值的任何变化都会立即反映在它们的返回中,反之亦然。简而言之,您不必担心它们。

(4) 是的,树控制器将观察虚拟属性而不是真实属性。如果虚拟属性不符合 KVO,控制器将无法工作。

(5) 历史上 NSTreeController 一直被认为是有缺陷的。它自 IIRC 2004 年以来一直存在,但从未真正发挥过作用。很多老手完全忽略了它。我已经有一段时间没有使用它了。

(6) 您通常只缓存预计不会发生太大变化的数据。如果提取用于实际更新模型或需要其他内容(例如 URL 请求)来更新模型,则不应使用缓存。

I don't think that the current version of NSTreeController requires attributes actually named "children" and "parent". You can use setChildrenKeyPath: to set the child path to any attribute name (as long as the attribute implements a parent-child hierarchy.) I'm pretty sure that is a rather old requirement. (Take that with a grain of salt, I haven't used the tree controller in sometime. See below)

As for your other questions:

(1) Yes

(2) Yes, yes and yes

(3) The relationships are maintained in the true attributes e.g. property. The entity/object graph is separate from the virtual graph that parent-child properties virtualize. Since the parent and child attributes do not actually have values, any change in the real values is immediately reflected in their return and vice versa. In short, you don't have to worry about them.

(4) Yes, the tree controller will be observing the virtual properties and not the real ones. If the virtual properties are not KVO compliant the controller will not work.

(5) Historically NSTreeController has been considered buggy. It has been around since IIRC 2004 and it never really worked well. A lot of old hands just ignore it completely. I haven't used it in some time.

(6) You generally only cache data that is not expected to change much. If the fetch is used to actually update the model or something else is expected to update the model e.g. a URL request, then you should not use a cache.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文