KVC
NSKeyValueCoding 協(xié)議 鍵值編碼(key-value)桅打,指定的key獲取對應(yīng)value;
一個類中的私有變量,不能直接通過Setter葛闷、Getter方法訪問霹陡。但是卻可以通過KVC來訪問和蚪。利用kvc的這個特性,我們可以訪問系統(tǒng)里的一些私有變量烹棉。
valueForKey:
setValue:@"" forKey:@"keypath";
可以直接設(shè)置key攒霹,keyPath 為屬性和成員變量名稱;Key:只能訪問當(dāng)前對象的屬性
KeyPath:能利用運(yùn)算符一層一層往內(nèi)部訪問屬性浆洗;
<1> .語法 和 kvc
在實(shí)現(xiàn)了訪問器方法的類中催束,使用點(diǎn)語法和KVC訪問對象其實(shí)差別不大,二者可以任意混用辅髓;
<2> kvc 中的數(shù)值和數(shù)據(jù)結(jié)構(gòu)
NSNumber 是一般基礎(chǔ)數(shù)據(jù)類型的對象泣崩;
NSValue 主要是對一些結(jié)構(gòu)體型的數(shù)據(jù)和自定義的數(shù)據(jù)結(jié)構(gòu)類型;
那么我們對應(yīng)屬性名稱作為 keyPath洛口,系統(tǒng)是如何幫助我們查找到對應(yīng)成員變量和屬性的呢矫付?
① 檢查是否存在-<key>、-is<key>(只針對布爾值有效)或者-get<key>的訪問器方法第焰,如果有可能买优,就是用這些方法返回值;
檢查是否存在名為-set<key>:的方法,并使用它做設(shè)置值杀赢。對于-get<key>和-set<key>:方法烘跺,將大寫Key字符串的第一個字母,并與Cocoa的方法命名保持一致脂崔;
②如果上述方法不可用滤淳,則檢查名為-_<key>、-_is<key>(只針對布爾值有效)砌左、-_get<key>和-set<key>:方法脖咐;
③如果沒有找到訪問器方法,可以嘗試直接訪問實(shí)例變量汇歹。實(shí)例變量可以是名為:<key>或<key>;
④如果仍未找到屁擅,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常产弹,我們可以根據(jù)需要重寫派歌。
異常處理 valueForUndefinedKey:
/* Given that an invocation of -valueForKey: would be unable to get a keyed value using its default access mechanism, return the keyed value using some other mechanism. The default implementation of this method raises an NSUndefinedKeyException. You can override it to handle properties that are dynamically defined at run-time.
*/
對于 NSDictionary objectForkey: 與 valueForKey:區(qū)別
一般來說 key 可以是任意字符串組合,如果 key 不是以 @ 符號開頭痰哨,這時候 valueForKey: 等同于 objectForKey:胶果,如果是以 @ 開頭,去掉 key 里的 @ 然后用剩下部分作為 key 執(zhí)行 [super valueForKey:]作谭。
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"theValue" forKey:@"@theKey"];
NSString *value1 = [dict objectForKey:@"@theKey"];
NSString *value2 = [dict valueForKey:@"@theKey"];
value1 ok, value2 crash
NSUnknownKeyException’, reason: ‘[<__NSCFDictionary 0x892fd80> valueForUndefinedKey:]:
在 KVC 里可以通過 property 同名字符串來獲取對應(yīng)的值稽物。 @"@theKey"會轉(zhuǎn)成@"theKey",沒有同名執(zhí)行valueForUndefinedKey 拋出異常折欠;
KVO
NSObject(NSKeyValueObserving)
- 注冊監(jiān)聽
- 監(jiān)聽事件處理
- 取消監(jiān)聽
當(dāng)某個類的對象第一次被觀察時贝或,系統(tǒng)就會在運(yùn)行期動態(tài)地創(chuàng)建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的 setter 方法锐秦。
派生類在被重寫的 setter 方法實(shí)現(xiàn)真正的通知機(jī)制咪奖,就如前面手動實(shí)現(xiàn)鍵值觀察那樣。這么做是基于設(shè)置屬性會調(diào)用setter方法酱床,通過下面兩個方法實(shí)現(xiàn):
- (void)willChangeValueForKey:(NSString *)key
- (void)didChangeValueForKey:(NSString *)key羊赵;
didChangeValueForKey 會處理:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);
KVO 和 NSNotificationCenter 蘋果實(shí)現(xiàn)是只保存了個對象的地址,并沒有在銷毀的時候置為nil扇谣。所以 addObserver后昧捷,必須要有remove操作。