2010-05-20 2 views
1

Мой пользовательский интерфейс не обновляется, когда я его ожидаю.с использованием KVO для обновления NSTableView, отфильтрованного NSPredicate

Приложение отображает «проекты», используя вид, аналогичный iTunes. Список источников слева позволяет вам фильтровать список (NSTableView) справа. Мои фильтры обновляются правильно, когда они изучают любое простое поле (например, имя, строка), но не для массивов (например, тегов).

Я удаляю тег из одного из моих объектов (из поля NSMutableArray, называемого «тегами»), и я ожидаю, что он исчезнет из списка, потому что он больше не соответствует предикату, привязанному к NSArrayController моей таблицы.

ProjectBrowser.mm:

self.filter = [NSPredicate predicateWithFormat:@"%@ IN %K", 
               selectedTag, 
               @"tags"]; 

Project.mm:

[self willChangeValueForKey:@"tags"]; 
[tags removeAllObjects]; 
[self didChangeValueForKey:@"tags"]; 

Я также попытался это, но результат тот же:

установка
[[self mutableArrayValueForKey:@"tags"] removeAllObjects]; 

Interface Builder :

  • объект ProjectBrowser является в XIb в файле Владелец
  • NSArrayController (Controller Project) имеет массив содержимого, связанного с «файла Владелец» .projects
  • фильтр предиката Диспетчерская Проектной обязан «Владелец файла» .filter
  • Столбец NSTableView привязан к «Project Controller» .name

ответ

2

Я нашел это в документации (KVC Compliance - Dependent Values):

Важно: Обратите внимание, что вы не можете настроить зависимости от ко-многим. Например, предположим, что у вас есть объект со многими отношениями (orderItems) к коллекции . Объекты OrderItem и объекты OrderItem имеют атрибут цены. Вам может потребоваться, чтобы объект Order имел атрибут totalPrice, который равен в зависимости от цен на все . Объекты OrderItem в отношениях. Вы не можете сделать это, реализовав keyPathsForValuesAffectingValueForKey: и возвращающий orderItems.price как ключевой путь для totalPrice.Вы должны наблюдать за атрибутом цены каждого из объектов OrderItem в orderItems коллекции и отвечать на Изменения в их значениях, обновляя totalPrice самостоятельно.

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

Когда я добавить проект в "проекты" массива:

[newProject addObserver:self forKeyPath:@"tags" options:NSKeyValueObservingOptionNew context:nil]; 

И важная часть:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([object isKindOfClass:[CProject class]] && [keyPath isEqualToString:@"tags"]) 
    { 
     [self willChangeValueForKey:@"projects"]; 
     [self didChangeValueForKey:@"projects"]; 
    } 
} 

И очистки, когда я удалить проект:

[project removeObserver:self forKeyPath:@"tags"]; 

Не уверен, что это лучшее решение, но оно обновляет мой список.

0

Я очень удивлен, что ваш первый фрагмент кода даже компилируется. Он также может не совсем работа, как вы ожидаете, потому что

self.property = foo; 

является синтаксически

[себе SetProperty: Foo];

В любом случае, ваша проблема может быть то, что вы не наблюдаете tags. Я не уверен, что предикат автоматически замечает ключи в своей строке запроса.

+0

Благодарим вас за указание на синтаксическую ошибку, возникшую во время моей попытки извлечь соответствующий код. Я исправил его выше. – KingRufus

+0

Я не наблюдаю за тегами, но предикат, кажется, замечает простые поля, когда это необходимо. Этот фильтр обновляет список всякий раз, когда имя изменяется: [.. predicateWithFormat: @ "% K ==% @", @ "name", selectedName] Поэтому, если я не распространяю уведомление об изменении, несмотря на мои усилия выше, как можно Я это исправим? Способность KVO наблюдать за использованием ключевых путей, таких как «project.someObject.someField», заставляет меня думать, что эти изменения должны «пузыриться» до наблюдателя, не требуя кода клея на каждой ссылке в цепочке/пути. В настоящее время массивы разрушают любую цепочку в функциональности ключа, отслеживающей ключевые слова моего кода. – KingRufus

+0

Другое предположение: возможно, предикат оптимизирует ваше изменение, потому что вы не меняете сам объект тегов. Попробуйте '[tag release]; tags = [[NSMutableArray alloc] init]; 'вместо' [tags removeAllObjects] ' – JeremyP