NSMutableDictionary KVO - PullRequest
       7

NSMutableDictionary KVO

5 голосов
/ 08 марта 2012

Я пытаюсь наблюдать изменения в словаре, используя KVO.

Пример:

dictionary = [NSMutableDictionary new];
[dictionary setObject:@"test1" forKey:@"key1"];
[dictionary setObject:@"test2" forKey:@"key2"];    
[dictionary setObject:@"test3" forKey:@"key1"];

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

Итак, в заключение: я хочу, чтобы функция вызывала

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

при добавленииЛюбая новая запись в словаре, или Удалить любую запись, или ЗАМЕНИТЬ любую запись.

НЕ: Я НЕ хочу указывать, какие ключи я наблюдаю.(например, соблюдать только при добавлении @ "key1"), поскольку это решение не масштабируется.

Ответы [ 5 ]

8 голосов
/ 08 марта 2012

Создание подклассов NSMutableDictionary немного раздражает из-за того, что NSDictionary и его друзья являются кластерами классов.Это, безусловно, выполнимо, и если вам нужно передать сам объект другому набору классов, то вы можете сделать именно это.В противном случае может быть проще создать составной класс, который имеет тот же базовый API и использует объект NSMutableDictionary для хранения внутри.Существует довольно хорошая статья, как CocoaWithLove.com, Упорядоченное подклассификация словаря , которая идет на это.

Однако это не полностью решает вашу проблему.Я хотел бы предложить, чтобы вы начали с подкласса или класса декоратора, такого как приведенный выше, а затем явно добавили поддержку для -(NSArray*)allKeys, который является стандартным средством доступа в самом NSDictionary.Затем вы можете добавить поддержку для передачи сообщений об изменениях для всех ключей, что сделает его наблюдаемым.

Это можно сделать, добавив следующий код вокруг методов -setObject:forKey: и -removeObjectForKey:.

- (void)setObject:(id)anObject forKey:(id)aKey
{
    BOOL addKey=NO;
    if (![dictionary objectForKey: aKey]) {
        addKey=YES;
        [self willChangeValueForKey: @"allKeys"];   
    }
    [dictionary setObject:anObject forKey:aKey];
    if (addKey)
        [self didChangeValueForKey: @"allKeys"];
}

- (void)removeObjectForKey:(id)aKey
{
    [self willChangeValueForKey: @"allKeys"];
    [dictionary removeObjectForKey:aKey];
    [self didChangeValueForKey: @"allKeys"];
}

Что здесь делается, так это то, что мы добавляем явное уведомление KVO в класс, когда ключи словаря изменены, чтобы пометить изменение в массиве.,Если вы хотите, чтобы об изменениях уведомляли на той же основе, вы можете удалить операторы if и просто сделать так, чтобы allKeys уведомлял об их установке или удалении, как показано ниже:в одном наблюдателе для ключа @ "allKeys" на этом объекте, и вы будете получать уведомления при каждом изменении элемента.

1 голос
/ 03 ноября 2016

Я решил похожую проблему, добавив наблюдателя в изменяемый словарь «переводчик» следующим образом:

[self addObserver:self forKeyPath:@"translator.@count" options:0 context:NULL];

Мое приложение обрабатывает данные классическим способом, используя табличное представление, контроллер и словарь в качестве свойства KVO "транслятор". Словарь привязан к NSDictionaryController в моем XIB, а содержимое табличного представления привязано к контроллеру.

Это соединения таблицы:

enter image description here

Теперь в любом из следующих случаев я улавливаю изменение:

  • добавление пары ключ-значение
  • удаление пары ключ-значение
  • смена ключа
  • изменение значения

Примечание: к сожалению, этот подход не работает с NSMutableArrays. Изменения не распознаются

0 голосов
/ 30 мая 2014

Я думаю, что другой способ сделать это - использовать приведенное ниже переопределение, если вы наблюдаете NSMutableDictionary "allRecentCurrencyData", значения которого зависят от latestBrazilReals, latestEuEuro, RecentUkPounds, latestJapanYen, будет вызван наблюдатель, но недостатком является то, что вам нужнознать ключи перед рукой, чтобы сделать это.

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"allRecentCurrencyData"]) {
       NSArray *affectingKeys = @[@"recentBrazilReals", @"recentEuEuro",@"recentUkPounds",@"recentJapanYen"];
      keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}
0 голосов
/ 03 мая 2014

Надеюсь, это будет полезно

- (void)addObserver:(id)observer {
    for (id key in grid)
        [self addObserver:observer
               forKeyPath:[key description]
                  options:0
                  context:key];
}
0 голосов
/ 08 марта 2012

Не можете ли вы создать подкласс NSMutableDictionary и переопределить различные сеттеры?Например, переопределение setObject: forKey: путем вызова super, а затем немедленного вызова addObserver ...

Вы также можете написать оболочку для NSMutableDictionary, где вы заставляете себя использовать пользовательские установщики для манипулирования базовым NSMutableDictionary.

Может быть, мне нужно больше контекста для любых ваших ограничений или масштабируемых намерений.

...