KVO實(shí)現(xiàn)原理

KVO實(shí)現(xiàn)原理

一陋桂,概述

KVO,Key-value Observing章喉,它提供一種機(jī)制汗贫,當(dāng)制定的對象的屬性被修改后秸脱,其觀察者就會接收到通知落包,簡單的說就是每次指定的被觀察的對象的屬性被修改后摊唇,KCO就會自動通知相應(yīng)的觀察者了咐蝇。

KVO其實(shí)也是觀察者模式的一種應(yīng)用,這種模式有利于兩個(gè)類之間的解耦合巷查。

二/KVO的具體實(shí)現(xiàn)

@interface ViewController ()

@property (strong, nonatomic) Person *p1;

@end

@implementation ViewController

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // 1.什么是通知 
    // 3個(gè)對象 
    self.p1 = [[Person alloc] init];
    self.p1.name = @"p1"; 
    //打印監(jiān)聽前類信息 
    [p1 printInfo]; 
    // KVO是監(jiān)聽對象的屬性值的改變的 
    [self.p1 addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 
    self.p1.name = @"123"; 
    //打印監(jiān)聽后類信息 
    [p1 printInfo]; 
    [p1 removeObserver:self forKeyPath:@"name"]; 
    //打印移除監(jiān)聽后類信息 [p1 printInfo]; } 
    // 這個(gè)方法時(shí)屬于 NSObject 類的,任何對象都可以作為觀察者 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { NSLog(@"監(jiān)聽到了%@的%@屬性發(fā)生了改變", object, keyPath); NSLog(@"%@", change); }

@end

 person類方法: 
 -(void)printInfo { 
    NSLog(@"isa:%@, supper class:%@", NSStringFromClass(object_getClass(self)), class_getSuperclass(object_getClass(self))); 
    NSLog(@"self:%@, [self superclass]:%@", self, [self superclass]); 
    NSLog(@"age setter function pointer:%p", class_getMethodImplementation(object_getClass(self), @selector(setAge:))); 
    NSLog(@"name setter function pointer:%p", class_getMethodImplementation(object_getClass(self), @selector(setName:))); 
    NSLog(@"printInfo function pointer:%p", class_getMethodImplementation(object_getClass(self), @selector(printInfo))); }

三旭寿、KVO的實(shí)現(xiàn)原理

KVO 是基于運(yùn)行時(shí)實(shí)現(xiàn)的 isa Class NSKVONotifying_Person

基本的原理:當(dāng)觀察某對象A時(shí)崇败,KVO機(jī)制動態(tài)創(chuàng)建一個(gè)對象A當(dāng)前類的子類缩膝,并為這個(gè)新的子類重寫了被觀察屬性keyPath的setter 方法。setter 方法隨后負(fù)責(zé)通知觀察對象屬性的改變狀況疾层。

深入刨析

Apple 使用了 isa 混寫(isa-swizzling)來實(shí)現(xiàn) KVO 痛黎。當(dāng)觀察對象A時(shí),KVO機(jī)制動態(tài)創(chuàng)建一個(gè)新的名為: NSKVONotifying_A的新類贸桶,該類繼承自對象A的本類舅逸,且KVO為NSKVONotifying_A重寫觀察屬性的setter 方法,setter 方法會負(fù)責(zé)在調(diào)用原 setter 方法之前和之后皇筛,通知所有觀察對象屬性值的更改情況。(備注: isa 混寫(isa-swizzling)isa:is a kind of 坠七; swizzling:混合水醋,攪合旗笔;)

①NSKVONotifying_A類剖析:在這個(gè)過程,被觀察對象的 isa 指針從指向原來的A類拄踪,被KVO機(jī)制修改為指向系統(tǒng)新創(chuàng)建的子類 NSKVONotifying_A類蝇恶,來實(shí)現(xiàn)當(dāng)前類屬性值改變的監(jiān)聽;

所以當(dāng)我們從應(yīng)用層面上看來惶桐,完全沒有意識到有新的類出現(xiàn)撮弧,這是系統(tǒng)“隱瞞”了對KVO的底層實(shí)現(xiàn)過程,讓我們誤以為還是原來的類姚糊。但是此時(shí)如果我們創(chuàng)建一個(gè)新的名為“NSKVONotifying_A”的類()贿衍,就會發(fā)現(xiàn)系統(tǒng)運(yùn)行到注冊KVO的那段代碼時(shí)程序就崩潰,因?yàn)橄到y(tǒng)在注冊監(jiān)聽的時(shí)候動態(tài)創(chuàng)建了名為NSKVONotifying_A的中間類救恨,并指向這個(gè)中間類了贸辈。(isa 指針的作用:每個(gè)對象都有isa 指針,指向該對象的類肠槽,它告訴 Runtime 系統(tǒng)這個(gè)對象的類是什么擎淤。所以對象注冊為觀察者時(shí),isa指針指向新子類秸仙,那么這個(gè)被觀察的對象就神奇地變成新子類的對象(或?qū)嵗┝俗炻!#?因而在該對象上對 setter 的調(diào)用就會調(diào)用已重寫的 setter,從而激活鍵值通知機(jī)制寂纪。

②子類setter方法剖析:KVO的鍵值觀察通知依賴于 NSObject 的兩個(gè)方法:willChangeValueForKey:和 didChangevlueForKey:席吴,在存取數(shù)值的前后分別調(diào)用2個(gè)方法:被觀察屬性發(fā)生改變之前,willChangeValueForKey:被調(diào)用弊攘,通知系統(tǒng)該 keyPath 的屬性值即將變更抢腐;當(dāng)改變發(fā)生后, didChangeValueForKey: 被調(diào)用襟交,通知系統(tǒng)該 keyPath 的屬性值已經(jīng)變更迈倍;之后observeValueForKey:ofObject:change:context: 也會被調(diào)用。且重寫觀察屬性的setter 方法這種繼承方式的注入是在運(yùn)行時(shí)而不是編譯時(shí)實(shí)現(xiàn)的捣域。

上述例子中啼染,當(dāng) p1.name 的值改變時(shí),p1對象的 isa 指針會指向 NSKVONotifying_Person焕梅,意味著迹鹅,在程序運(yùn)行時(shí),會動態(tài)生成一個(gè) NSKVONotifying_Person 類贞言,該類繼承于 Person斜棚,而且該類中也有個(gè) -setName: 方法,方法中在設(shè)置 name 的同時(shí)實(shí)現(xiàn)了:

四、特點(diǎn)

觀察者觀察的是屬性弟蚀,只有遵循 KVO 變更屬性值的方式才會執(zhí)行KVO的回調(diào)方法蚤霞,例如是否執(zhí)行了setter方法、或者是否使用了KVC賦值义钉。

如果賦值沒有通過setter方法或者KVC昧绣,而是直接修改屬性對應(yīng)的成員變量,例如:僅調(diào)用_name = @"newName"捶闸,這時(shí)是不會觸發(fā)kvo機(jī)制夜畴,更加不會調(diào)用回調(diào)方法的。

所以使用KVO機(jī)制的前提是遵循 KVO 的屬性設(shè)置方式來變更屬性值删壮。

拓展

1.KVC與KVO的不同贪绘?

KVC(鍵值編碼),即Key-Value Coding醉锅,一個(gè)非正式的Protocol兔簇,使用字符串(鍵)訪問一個(gè)對象實(shí)例變量的機(jī)制。而不是通過調(diào)用Setter硬耍、Getter方法等顯式的存取方式去問垄琐。

KVO(鍵值監(jiān)聽),即Key-Value Observing经柴,它提供一種機(jī)制,當(dāng)指定的對象的屬性被修改后,對象就會接受到通知狸窘,前提是執(zhí)行了setter方法、或者使用了KVC賦值坯认。

2.和notification(通知)的區(qū)別翻擒?

notification比KVO多了發(fā)送通知的一步。兩者都是一對多牛哺,但是對象之間直接的交互陋气,notification明顯得多,需要notificationCenter來做為中間交互引润。而KVO如我們介紹的巩趁,設(shè)置觀察者->處理屬性變化,至于中間通知這一環(huán)淳附,則隱秘多了议慰,只留一句“交由系統(tǒng)通知”,具體的可參照以上實(shí)現(xiàn)過程的剖析奴曙。

notification的優(yōu)點(diǎn)是監(jiān)聽不局限于屬性的變化别凹,還可以對多種多樣的狀態(tài)變化進(jìn)行監(jiān)聽,監(jiān)聽范圍廣洽糟,例如鍵盤炉菲、前后臺等系統(tǒng)通知的使用也更顯靈活方便堕战。(參照通知機(jī)制第五節(jié)系統(tǒng)通知名稱內(nèi)容)

3.與delegate的不同?

和delegate一樣颁督,KVO和NSNotification的作用都是類與類之間的通信践啄。但是與delegate不同的是:

這兩個(gè)都是負(fù)責(zé)發(fā)送接收通知浇雹,剩下的事情由系統(tǒng)處理沉御,所以不用返回值;而delegate 則需要通信的對象通過變量(代理)聯(lián)系昭灵;

delegate一般是一對一吠裆,而這兩個(gè)可以一對多。

4.涉及技術(shù):

KVC/KVO實(shí)現(xiàn)的根本是Objective-C的動態(tài)性和runtime烂完,以及訪問器方法的實(shí)現(xiàn)试疙;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抠蚣,隨后出現(xiàn)的幾起案子祝旷,更是在濱河造成了極大的恐慌,老刑警劉巖嘶窄,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怀跛,死亡現(xiàn)場離奇詭異,居然都是意外死亡柄冲,警方通過查閱死者的電腦和手機(jī)吻谋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來现横,“玉大人漓拾,你說我怎么就攤上這事〗潇簦” “怎么了骇两?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姜盈。 經(jīng)常有香客問我低千,道長,這世上最難降的妖魔是什么贩据? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任栋操,我火速辦了婚禮,結(jié)果婚禮上饱亮,老公的妹妹穿的比我還像新娘矾芙。我一直安慰自己,他們只是感情好近上,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布剔宪。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葱绒。 梳的紋絲不亂的頭發(fā)上感帅,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音地淀,去河邊找鬼失球。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帮毁,可吹牛的內(nèi)容都是我干的实苞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼烈疚,長吁一口氣:“原來是場噩夢啊……” “哼黔牵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起爷肝,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤猾浦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后灯抛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體金赦,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年牧愁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了素邪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猪半,死狀恐怖兔朦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磨确,我是刑警寧澤沽甥,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站乏奥,受9級特大地震影響摆舟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邓了,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一恨诱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骗炉,春花似錦照宝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兢仰。三九已至,卻和暖如春剂碴,著一層夾襖步出監(jiān)牢的瞬間把将,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工忆矛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留察蹲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓洪碳,卻偏偏與公主長得像递览,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子瞳腌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 報(bào)名的時(shí)候看到學(xué)校的第一眼我就很失望了。不是想象中的校園镜雨,有的只是看起來很舊的教學(xué)樓嫂侍,面積也是小的可憐。其實(shí)也不能...
    陌上花開若如初見不如不見閱讀 1,732評論 0 1
  • 追風(fēng)箏的人,平平淡淡中演繹了真情颓影。為你各淀,千千萬萬次,哈桑忠誠到底诡挂,一個(gè)眼神承擔(dān)了世上僅有的一種罪---偷竊碎浇。為你,...
    Amos_gouge閱讀 372評論 0 0
  • 九十年代的大學(xué)生流行逃票出行璃俗,就仿佛現(xiàn)在的年輕人結(jié)婚有房要車是其標(biāo)配一樣奴璃。 張生同學(xué)乘火車逃票自有...
    層林盡染林溪邊閱讀 675評論 0 1
  • 似睡非睡 潛意識還是有對你濃濃地思念 想象我們初次見面的樣子 想象你緊緊擁抱我地樣子 想象你溫柔深情親吻我的樣子 ...
    田小姣閱讀 273評論 0 1