我正在尝试使用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”时观察),因为此解决方案无法缩放。
答案 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的连接:
现在,在以下任何一种情况下,我都会发现变化:
备注:遗憾的是,这种方法不适用于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;
}