NSMutableDictionary KVO

时间:2012-03-08 02:04:58

标签: objective-c key-value-observing

我正在尝试使用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
当我向字典添加任何新条目,或删除任何条目或替换任何条目时,

被调用。

NOT:我不想指定我正在观察的键。 (例如,仅在添加@“key1”时观察),因为此解决方案无法缩放。

5 个答案:

答案 0 :(得分:7)

子类化NSMutableDictionary有点烦人,因为NSDictionary及其朋友是类集群。它肯定是可行的,如果你必须将对象本身传递给另一组类,那么你可能想要做到这一点。否则,可能更容易创建具有相同基本API的复合类,并在内部使用NSMutableDictionary对象进行存储。作为CocoaWithLove.com,Ordered Dictionary Subclassing,有一个非常好的写作,这是为了做到这一点。

然而,这并不能完全解决您的问题。我建议您从上面的子类或装饰器类开始,然后为-(NSArray*)allKeys显式添加支持,NSDictionary本身是-setObject:forKey:中的标准访问器。然后,您可以添加支持以传递allKeys的更改消息,这将使其可观察。

可以通过在-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"]; } 方法周围添加以下代码来完成此操作。

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

这里要做的是,当字典的键被更改为标记数组中的更改时,我们将向类中添加显式KVO通知。

这将负责添加和删除。如果您希望以相同的方式通知更改,则可以删除if语句,只需在设置或删除时通知allKeys,如下所示:

{{1}}

然后,在你的代码中,你在这个对象上输入了一个密钥@“allKeys”的观察者,并且你会在项目发生变化时收到通知。

答案 1 :(得分:1)

我通过在可变字典中添加一个观察者解决了类似的问题"翻译"这样:

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

我的应用程序以经典的方式管理数据,使用tableview,控制器和字典作为KVO属性"翻译"。 字典绑定到我的XIB中的NSDictionaryController,并且tableview内容绑定到控制器。

这是tableview的连接:

enter image description here

现在,在以下任何一种情况下,我都会发现变化:

  • 添加键值对
  • 删除键值对
  • 更改密钥
  • 更改值

备注:遗憾的是,这种方法不适用于NSMutableArrays。 无法识别变更

答案 2 :(得分:0)

你不能继承NSMutableDictionary并覆盖各种setter吗?例如,重写setObject:forKey:通过调用super,然后立即调用addObserver ...

您还可以为NSMutableDictionary编写一个包装器,强制自己使用自定义setter来操作底层的NSMutableDictionary。

也许我需要更多的上下文来处理您的任何限制或可扩展性意图。

答案 3 :(得分:0)

我希望这会有所帮助

- (void)addObserver:(id)observer {
    for (id key in grid)
        [self addObserver:observer
               forKeyPath:[key description]
                  options:0
                  context:key];
}

答案 4 :(得分:0)

我认为另一种方法是使用下面的覆盖,如果您正在观察NSMutableDictionary“allRecentCurrencyData”,其值依赖于recentBrazilReals,recentEuEuro,recentUkPounds,recentJapanYen,观察者将被调用,但缺点是您需要事先知道钥匙。

+ (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;
}