简单粗暴地observe一个NSArray对象

在 iOS 开发中,KVO 是一个非常好的工具 (虽然用法比较操蛋)。我们常常用它来分离 Model 和 Controller 之间的一些依赖关系。但是却不太容易对 To-many 关系 (NSArray, NSSet, NSDictionary) 的内容变化进行监听。

Observe NSArray

今天查了官方文档和很多网上资料,推荐一种简单直接的方式对 NSArray 的内容变化进行监听。例如,你需要给 nameArray 增加一个 name,使用常规方法不会触发 KVO, [nameArray addobject:name]

而使用 -mutableArrayValueForKey: 来替代 nameArray 就可以触发 KVO 了,

[[self mutableArrayValueForKey:@"nameArray"] addObject:name];

而且, 观察者得到的 change 字典中,会有详细的修改信息供参考:是增加还是删除还是修改,改了什么,都可以很明确的得到这些信息。例如,

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (![keyPath isEqualToString:@"nameArray"]) return;
    
    NSKeyValueChange kindKey = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
    
    if (kindKey == NSKeyValueChangeInsertion) {
    
        NSString *name = [change[NSKeyValueChangeNewKey] firstObject];

    } else if (kindKey == NSKeyValueChangeReplacement) {

        NSString *oldName = [change[NSKeyValueChangeOldKey] firstObject];
        NSString *newName = [change[NSKeyValueChangeNewKey] firstObject];

    }
    ...
}

副作用: 修改后的 nameArray 是被拷贝的。也是就说内存地址会变化,如果有其他对象也持有这个数组,就要注意不要踩坑。

涉及 KVC 的另一种方式

还有一种方法, 涉及 KVC, 要 override 掉 NSArray 的 Accessors, 我认为很麻烦,而且要写一堆方法在观察者的类中。若无特殊需求, 不推荐这种方式, 处理起来太累了。

Observe NSSet / NSDictionary

NSSet 和 NSArray 差不多。使用 -mutableSetValueForKey:即可。
NSDictionary 就呵呵了,暂时没发现啥好方法。手动触发吧。

[self willChangeValueForKey:self.dict];
[self.dict setObject:object forKey:key];
[self didChangeValueForKey:self.dict];


参考
NSKeyValueCoding Protocol Reference
KVC Accessors
第九块石头:可变长度对象在KVO中的实现


欢迎来我的个站逛逛: http://alexyu.me/

你可能感兴趣的:(简单粗暴地observe一个NSArray对象)