在 iOS 開(kāi)發(fā)中,KVO 是一個(gè)非常好的工具 (雖然用法比較操蛋)逞度。我們常常用它來(lái)分離 Model 和 Controller 之間的一些依賴(lài)關(guān)系。但是卻不太容易對(duì) To-many 關(guān)系 (NSArray, NSSet, NSDictionary) 的內(nèi)容變化進(jìn)行監(jiān)聽(tīng)。
Observe NSArray
今天查了官方文檔和很多網(wǎng)上資料泳姐,推薦一種簡(jiǎn)單直接的方式對(duì) NSArray 的內(nèi)容變化進(jìn)行監(jiān)聽(tīng)。例如暂吉,你需要給 nameArray
增加一個(gè) name
胖秒,使用常規(guī)方法不會(huì)觸發(fā) KVO, [nameArray addobject:name]
。
而使用 -mutableArrayValueForKey:
來(lái)替代 nameArray
就可以觸發(fā) KVO 了,
[[self mutableArrayValueForKey:@"nameArray"] addObject:name];
而且, 觀察者得到的 change
字典中慕的,會(huì)有詳細(xì)的修改信息供參考:是增加還是刪除還是修改阎肝,改了什么,都可以很明確的得到這些信息肮街。例如,
- (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
是被拷貝的风题。也是就說(shuō)內(nèi)存地址會(huì)變化,如果有其他對(duì)象也持有這個(gè)數(shù)組嫉父,就要注意不要踩坑俯邓。
涉及 KVC 的另一種方式
還有一種方法, 涉及 KVC, 要 override 掉 NSArray 的 Accessors, 我認(rèn)為很麻煩,而且要寫(xiě)一堆方法在觀察者的類(lèi)中熔号。若無(wú)特殊需求, 不推薦這種方式, 處理起來(lái)太累了稽鞭。
Observe NSSet / NSDictionary
NSSet 和 NSArray 差不多。使用 -mutableSetValueForKey:
即可引镊。
NSDictionary 就呵呵了朦蕴,暫時(shí)沒(méi)發(fā)現(xiàn)啥好方法。手動(dòng)觸發(fā)吧弟头。
[self willChangeValueForKey:self.dict];
[self.dict setObject:object forKey:key];
[self didChangeValueForKey:self.dict];
參考
NSKeyValueCoding Protocol Reference
KVC Accessors
第九塊石頭:可變長(zhǎng)度對(duì)象在KVO中的實(shí)現(xiàn)
歡迎來(lái)我的個(gè)站逛逛: http://alexyu.me/