NSOutlineView, NSTreeController и гетерогенная иерархия - PullRequest
1 голос
/ 20 июня 2010

На странице 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
  1. Следуетдочерние и родительские свойства будут в заголовочном файле?

  2. Это предлагаемая реализация?Должен ли я также включить addChildrenObject:, removeChildrenObject:, addChildren: и removeChildren:?И реализовать их?(То же самое относится и к родительским методам.)

  3. Я предполагаю, что дочерние элементы вообще не появляются в модели базовых данных.Это правильно?Как тогда выводятся обратные отношения?

  4. Должен ли я вызвать [self willChangeValueForKey: @ "children"] в setChildren: таким образом, children соответствует KVO?(То же самое для других методов доступа.)

  5. На стр. 41 М. Зарра рекомендует реализовать NSOutlineDataSource вместо использования NSTreeController из-за «результатов [которые] могут быть неожиданными и неясными».Кто-нибудь знает, каковы эти ограничения?

  6. Наконец, если я реализую NSOutlineDataSource, вы бы порекомендовали кэшировать выборку для корневых объектов?И если да, то как правильно поддерживать этот кэшированный массив в синхронизации с Core Data?

Спасибо.

С уважением,

Jorge

Ответы [ 2 ]

1 голос
/ 22 июня 2010

Проблема, которую я вижу здесь, состоит в том, что, хотя установка свойства children будет запускать KVO для свойства projects, обратное неверно. Таким образом, если вы добавите проект в объект библиотеки через отношение «projects», представление структуры не будет обновлено, поскольку не увидит никаких изменений в свойстве «children».

Самый простой способ включить это - реализовать такой метод:

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

Это должно внести любые изменения в свойство "projects", а также вызвать уведомление KVO для "children".

С другой стороны, поскольку свойство "children" не является частью вашей модели Core Data, я не думаю, что вызовы will/didAccessValueForKey: являются строго необходимыми, хотя я не думаю, что они повредят чему-либо. Кроме того, если вы реализуете метод, который я упомянул выше, вам больше не нужно вызывать will/didChangeValueForKey: в методе setChildren:, поскольку Cocoa должна автоматически вызывать KVO для этого при изменении ключа "projects".

1 голос
/ 20 июня 2010

Я не думаю, что текущая версия NSTreeController требует атрибутов, которые на самом деле называются "children" и "parent".Вы можете использовать setChildrenKeyPath:, чтобы установить дочерний путь к любому имени атрибута (при условии, что атрибут реализует иерархию родительский-дочерний.) Я уверен, что это довольно старое требование.(Возьмите это с крошкой соли, я когда-то не использовал контроллер дерева. См. Ниже)

Что касается других ваших вопросов:

(1) Да

(2) Да, да и да

(3) Отношения поддерживаются в истинных атрибутах, например, свойстве.Граф сущности / объекта отделен от виртуального графа, который виртуализируют свойства parent-child.Поскольку родительские и дочерние атрибуты на самом деле не имеют значений, любое изменение в реальных значениях немедленно отражается в их возвращении и наоборот.Короче говоря, вам не нужно беспокоиться о них.

(4) Да, контроллер дерева будет наблюдать виртуальные свойства, а не реальные.Если виртуальные свойства не соответствуют KVO, контроллер не будет работать.

(5) Исторически NSTreeController считался ошибочным.Он существует с IIRC 2004 года и никогда не работал хорошо.Многие старые руки просто игнорируют это.Я не использовал его в течение некоторого времени.

(6) Обычно вы кешируете только те данные, которые вряд ли сильно изменятся.Если выборка используется для фактического обновления модели или ожидается, что обновит модель что-то другое, например, запрос URL, то вам не следует использовать кеш.

...