转载

简单粗暴地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<NSString *,id> *)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中的实现
正文到此结束
Loading...