全稱(chēng)
- KVO: Key-Value-Observer
- KVC: Key-Value-Coding
KVO的使用
使用過(guò)程
監(jiān)聽(tīng)回調(diào)返回新值和舊值
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;添加監(jiān)聽(tīng)
[被監(jiān)聽(tīng)的實(shí)例對(duì)象 addObserver:監(jiān)聽(tīng)器 forKeyPath:屬性 options:options context:nil]監(jiān)聽(tīng)接收事件
- (void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionaryid> *)changecontext:(void*)context{ NSLog(@"%@--%@--%@",object,keyPath,change); }記得添加監(jiān)聽(tīng)和移除監(jiān)聽(tīng),需要配對(duì)使用
原理
測(cè)試類(lèi) Person
系統(tǒng)會(huì)生成NSKVONotifying_Person類(lèi),該類(lèi)繼承Person,并且將Person的isa指向NSKVONotifying_Person。
-
NSKVONotifying_Person從寫(xiě)監(jiān)控屬性的setter方法,內(nèi)部調(diào)用
_assetXXXValueAndNotify();
_assetXXXValueAndNotify內(nèi)部實(shí)現(xiàn):2.1
- (void)willChangeValueForKey:(NSString *)key;2.2
- (void)didChangeValueForKey:(NSString *)key;2.3
didChangeValueForKey里面調(diào)用[super didChangeValueForKey]時(shí),會(huì)觸發(fā)回調(diào)方法
- (void)observeValueForKeyPath:(NSString*)keyPathofObject: (id)objectchange:(NSDictionaryid> *)changecontext:(void*)context通知開(kāi)發(fā)者數(shù)據(jù)發(fā)生變化。
3.NSKVONotifying_Person內(nèi)部還會(huì)從寫(xiě) - (Class)class; 方法,目的是隱藏系統(tǒng)生成的類(lèi)。
4.如果需要手動(dòng)調(diào)用,只需要調(diào)用2個(gè)方法:
willChangeValueForKey
didChangeValueForKey
即可;
5.單純使用KVO,訪(fǎng)問(wèn)成員變量person -> age = 10;是不會(huì)觸發(fā)KVO監(jiān)聽(tīng)的。
KVC setValueForKey: 和setValueForKeyPath:
假如Person對(duì)象有個(gè)屬性叫age
setValueForKey
- 可以對(duì)實(shí)例對(duì)象的某個(gè)屬性賦值
setValueForKeyPath:入?yún)⑹锹窂剑?/h5>
可以對(duì)實(shí)例對(duì)象中的,某個(gè)對(duì)象的某個(gè)屬性,進(jìn)行賦值;例如入?yún)⒖梢允?person.data.num,就代表對(duì)person對(duì)象的data對(duì)象的num屬性進(jìn)行賦值
可以訪(fǎng)問(wèn)對(duì)象的隱藏屬性
-
可以求最大最小值,再也不用手動(dòng)遍歷數(shù)組求值了
求最大值:[array valueForKeyPath:@"@max.self"]
使用KVC賦值
可以對(duì)實(shí)例對(duì)象中的,某個(gè)對(duì)象的某個(gè)屬性,進(jìn)行賦值;例如入?yún)⒖梢允?person.data.num,就代表對(duì)person對(duì)象的data對(duì)象的num屬性進(jìn)行賦值
可以訪(fǎng)問(wèn)對(duì)象的隱藏屬性
可以求最大最小值,再也不用手動(dòng)遍歷數(shù)組求值了
求最大值:[array valueForKeyPath:@"@max.self"]
例如Person中有一個(gè)age屬性
查找順序
1.setAge:
2._setAge:假如上面2個(gè)方法都沒(méi)有實(shí)現(xiàn),則系統(tǒng)會(huì)調(diào)用是否允許直接訪(fǎng)問(wèn)成員變量方法:
+ (BOOL)accessInstanceVariablesDirectly
如果返回NO,則系統(tǒng)調(diào)用setValue:forUndefineKey,直接報(bào)NSUnknowKeyException異常;如果沒(méi)有setter方法,只有成員變量時(shí),并且
+ (BOOL)accessInstanceVariablesDirectly返回YES,KVO同樣可以監(jiān)測(cè)到屬性值發(fā)生了改變;
例如需要查找的屬性叫age,則查找順序如下
1. _age
2. _isAge
3. age
4. isAge
如果方法未找到,上面4個(gè)屬性也未找到,則會(huì)報(bào)上面的異常setValue:forUndefineKey
KVC取值 valueForKey: 和valueForKeyPath:
- 方法查找順序
1. getKey
2. key
3. isKey
4. _key
如果方法未找到,則會(huì)調(diào)用系統(tǒng)方法+ (BOOL)accessInstanceVariablesDirectly判斷是否可以直接訪(fǎng)問(wèn)成員變量,如果是NO,則會(huì)報(bào)valueForUndefineKey,如果是YES,則會(huì)按如下順序查找成員變量:
1. _key
2. _isKey
3. key
4. isKey