iOS - 《KVC與KVO》

KVC(Key-value coding)鍵值編碼,指iOS的開發(fā)中,可以允許開發(fā)者通過Key名直接訪問對象的屬性,或者給對象的屬性賦值。不需要調用明確的存取方法。這樣就可以在運行時動態(tài)地訪問和修改對象的屬性。而不是在編譯時確定,這也是iOS開發(fā)中的黑魔法之一。
KVC可以不通過getter/setter方法來訪問對象的屬性。
因為一個類的成員變量如果沒有提供getter/setter的話,外界就失去了對這個變量的訪問渠道。而KVC則提供了一種訪問的方法,這個在某些場合會很有威力。例如,直接修改系統(tǒng)控件的內部屬性

KVO 是 Objective-C 對觀察者設計模式的一種實現(xiàn)。【另外一種是:通知機制(notification)】;
KVO提供一種機制,指定一個被觀察對象(例如A類),當對象某個屬性(例如A中的字符串name)發(fā)生更改時,監(jiān)聽對象會獲得通知,并作出相應處理;【且不需要給被觀察的對象添加任何額外代碼,就能使用KVO機制】
在MVC設計架構下的項目,KVO機制很適合實現(xiàn)mode模型和view視圖之間的通訊。

KVC(Key-value coding)

下面是KVC最為重要的四個方法

- (nullable id)valueForKey:(NSString *)key;                          //直接通過Key來取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通過Key來設值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通過KeyPath來取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通過KeyPath來設值
+ (BOOL)accessInstanceVariablesDirectly;
//默認返回YES,表示如果沒有找到Set<Key>方法的話,會按照_key,_iskey,key,iskey的順序搜索成員,設置成NO就不這樣搜索

- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在,且沒有KVC無法搜索到任何和Key有關的字段或者屬性,則會調用這個方法,默認是拋出異常。

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一個方法一樣,但這個方法是設值。

- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法時面給Value傳nil,則會調用這個方法

修改系統(tǒng)控件的內部屬性(Runtime+KVC)

比如修改tabbar底部控制欄的tabbar為自定義tabbar類型,就可以通過kvc來實現(xiàn)。
有時候一些屬性是私有變量,可以通過runtime來查找屬性值

/**
 *  運行時(runtime),獲取所有成員變量
 */
- (void)getMemberVariables
{
    unsigned ivarCount;
    Ivar *ivars = class_copyIvarList([UIPageControl class], &ivarCount);
    
    for (int i = 0; i < ivarCount; i ++) {
        
        NSString *varibale = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
        
        NSLog(@"%@",varibale);
    }
}


通過KVC來修改
UIPageControl *pageControl = [[UIPageControl alloc ] init];
[pageControl setValue:[UIImage imageNamed:%@"nomal.png"] forKey:@"_pageImage"];
[pageControl setValue:[UIImage imageNamed:%@"selected.png"] forKey:@"_currentPageImage"]

KVC底層原理分析

setValue:forKey:賦值原理如下

  • 去模型中查找有沒有對應的setter方法:例如:setIcon方法,有就直接調用這個setter方法給模型這個屬性賦值[self setIcon:dic[@"icon"]];
  • 如果找不到setter方法,接著就會去尋找有沒有icon屬性,如果有,就直接訪問模型中的icon屬性,進行賦值,icon=dict[@"icon"];
  • 如果找不到icon屬性,接著又會去尋找_icon屬性,如果有,直接進行賦值_icon=dict[@"icon"];
  • 如果都找不到就會報錯:[<Flag 0X7fb74bc7a2c0> setValue:forUndefinedKey:]
  • 如果對某個類,不允許使用KVC,可以通過設置 accessInstanceVariablesDirectly 控制。
    KVC內部的實現(xiàn)

比如說如下的一行KVC的代碼:

[site setValue:@"sitename" forKey:@"name"];
就會被編譯器處理成:

SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");

這下KVC內部的實現(xiàn)就很清楚的清楚了:一個對象在調用setValue的時候,

  • (1)首先根據(jù)方法名找到運行方法的時候所需要的環(huán)境參數(shù)。
  • (2)他會從自己isa指針結合環(huán)境參數(shù),找到具體的方法實現(xiàn)的接口。
  • (3)再直接查找得來的具體的方法實現(xiàn)。

/
/
/
/
/

KVO

KVO 是 Objective-C 對觀察者設計模式的一種實現(xiàn)。【另外一種是:通知機制(notification)】;

KVO提供一種機制,指定一個被觀察對象(例如A類),當對象某個屬性(例如A中的字符串name)發(fā)生更改時,監(jiān)聽對象會獲得通知,并作出相應處理;【且不需要給被觀察的對象添加任何額外代碼,就能使用KVO機制】
在MVC設計架構下的項目,KVO機制很適合實現(xiàn)mode模型和view視圖之間的通訊。

notification比KVO多了發(fā)送通知的一步。

兩者都是一對多,但是對象之間直接的交互,notification明顯得多,需要notificationCenter來做為中間交互。而KVO如我們介紹的,設置觀察者->處理屬性變化,至于中間通知這一環(huán),則隱秘多了,只留一句“交由系統(tǒng)通知”,具體的可參照以上實現(xiàn)過程的剖析。
notification的優(yōu)點是監(jiān)聽不局限于屬性的變化,還可以對多種多樣的狀態(tài)變化進行監(jiān)聽,監(jiān)聽范圍廣,例如鍵盤、前后臺等系統(tǒng)通知的使用也更顯靈活方便。

與delegate的不同

和delegate一樣,KVO和NSNotification的作用都是類與類之間的通信。但是與delegate不同的是:
這兩個都是負責發(fā)送接收通知,剩下的事情由系統(tǒng)處理,所以不用返回值;而delegate 則需要通信的對象通過變量(代理)聯(lián)系;

delegate一般是一對一,而這兩個可以一對多。

KVO應用過程

1:注冊觀察者,實施監(jiān)聽;

[self.model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
- observer 指觀察者
- keyPath 表示被觀察者的屬性
- options 決定了提供給觀察者change字典中的具體信息有哪些。 【見options解析】
- context 這個參數(shù)可以是一個 C指針,也可以是一個 對象引用,它可以作為這個context的唯一標識,也可以提供一些數(shù)據(jù)給觀察者。因為你傳進去是啥,回調時候還是回傳的還是啥

注冊監(jiān)聽,options入?yún)⑹莻€枚舉,該入?yún)⒏O(jiān)聽回調中的change呼應。。并且,以上options入?yún)r候是可以用 | 或運算進行多選的。
例如:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld。。那在change字典中就會包含屬性變化前后的值。

2:監(jiān)聽回調

-observeValueForKeyPath:ofObject:change:context:就這一個方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    - keyPath:你所觀察對象的屬性
    - object:你所觀察的對象
    - change:你所觀察對象屬性值的變化
}

注意:通過多options監(jiān)聽屬性的時候,例如上,并不是回到一次老值,再回調一次新值,,而是新老值都是在change字典中的。。

3:移除觀察者

你可以通過 removeObserver:forKeyPath: 或 removeObserver:forKeyPath:context: 方法來移除一個觀察。
注意:如果你的 context 是一個 對象,你必須在移除觀察之前持有它的強引用。當移除了觀察后,觀察者對象再也不會受到這個 keyPath 的通知。

KVO的實現(xiàn)原理

當觀察某對象 A 時,KVO 機制動態(tài)創(chuàng)建一個對象A當前類的子類,并為這個新的子類重寫了被觀察屬性 keyPath 的 setter 方法。setter 方法隨后負責通知觀察對象屬性的改變狀況。

參考:

KVC

KVC的理解、應用及其底層原理 http://www.lxweimin.com/p/9839ecd75377
iOS開發(fā)技巧系列---詳解KVC(我告訴你KVC的一切)http://www.lxweimin.com/p/9839ecd75377

KVO

原文推薦前往閱讀:http://www.lxweimin.com/p/e59bb8f59302

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • KVC、KVO概述 KVC(NSKeyValueCoding) "鍵-值 編碼"是一種間接訪問對象的屬性的機制...
    Joker_King閱讀 1,010評論 1 4
  • KVC(Key-value coding)鍵值編碼,單看這個名字可能不太好理解。其實翻譯一下就很簡單了,就是指iO...
    黑暗中的孤影閱讀 49,859評論 74 441
  • 最近發(fā)現(xiàn)之前看的東西沒一會就忘記了,所以寫來好一些,也建議大家吧學到了記錄下來這樣加深印象,也可以幫助到別人。首先...
    _技術支持閱讀 935評論 1 1
  • 在我二十出頭含苞待放的年紀我就遇見了野人。那時候還沒有微信,QQ還是風靡一時的流行社交工具,有一次我準備進去裝修我...
    yellow小純子閱讀 86,516評論 1,130 986
  • 當你篤定的做自己,找到你自己的專屬節(jié)奏……找到你與這個世界獨特的對話方式……你從彎腰改成直立……你從追趕滿世界跑到...
    奧敖翱閱讀 255評論 0 0