iOS 用RunTime重寫KVO<附Demo>

簡介

KVO相信iOS開發(fā)者們都聽說過,在面試中也會(huì)被常常問到,但是呢對(duì)于KVO來說更多的事情是由系統(tǒng)來做的,依賴于運(yùn)行時(shí),相對(duì)于Notification,delegate來說是比較簡單的,提供觀察屬性舊值與新值,以下單純的說下自己對(duì)KVO的實(shí)現(xiàn)原理粗略理解,用RunTime重寫一下KVO,有理解不恰當(dāng)?shù)牡胤?請(qǐng)?zhí)岢?謝謝大家


KVO基本使用和使用場景<觀察者模式較完美地將目標(biāo)對(duì)象與觀察者對(duì)象解耦>

a.首先說一下使用場景:

?一個(gè)目標(biāo)對(duì)象管理所有依賴于目標(biāo)對(duì)象的觀察者,在自身狀態(tài)改變的時(shí)候主動(dòng)通知觀察者->能夠監(jiān)聽某個(gè)對(duì)象屬性值的改變<1對(duì)多>

b.基本使用步驟:

1.給目標(biāo)對(duì)象添加觀察者

代碼示例:

[dog addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

2.處理變更通知

當(dāng)KVO 監(jiān)聽到目標(biāo)對(duì)象屬性值改變后,就會(huì)調(diào)用這個(gè)方法,change這個(gè)字典保存了變更信息至扰,具體是哪些信息取決于注冊時(shí)的NSKeyValueObservingOptions

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object chan

ge:(NSDictionary *)change context:(void *)context;

3.移除

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;


探討:??

當(dāng)目標(biāo)對(duì)象調(diào)用了addObserver:self forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#> 方法發(fā)生了什么事情,那么我們改變?yōu)槌蓡T變量的時(shí)候,還會(huì)有作用嗎?

解答:runtime到底做了什么,這個(gè)才是重點(diǎn),runtime動(dòng)態(tài)的給目標(biāo)對(duì)象類添加了一個(gè)子類,重寫set方法,改變了isa指針

代碼示例:


KVO原理

KVO--鍵(key)-值(value)觀察(observing)---->設(shè)計(jì)模式中的觀察者模式;

某個(gè)類被第一次觀察的時(shí),系統(tǒng)會(huì)在運(yùn)行期動(dòng)態(tài)的創(chuàng)建一個(gè)該類的子類,然后在子類中重寫被觀察屬性的setter方法,在子類中的重寫的setter方法中實(shí)現(xiàn)真正的通知機(jī)制,子類除了重寫setter方法外還重寫了class方法其欺騙調(diào)用者子類就是原本的父類(內(nèi)部其實(shí)是將父類的isa指針指向子類),父類就成為了派生類的對(duì)象,所以該對(duì)象對(duì)setter方法的調(diào)用,就會(huì)調(diào)用被重寫子類的setter方法,激活通知機(jī)制,除此之外子類還重寫了dealloc方法來釋放資源

怎樣用RunTime來重寫KVO

1.在我們自己定義的仿KVO方法中來寫

示例代碼:

- (void)MBXB_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{?

? ? ? ? //搞事

}


2.實(shí)現(xiàn)步驟

a.動(dòng)態(tài)的生成一個(gè)類

動(dòng)態(tài)類名

NSString * oldClassName = NSStringFromClass([self class]);

NSString * newName = [@"NSMBXB_" stringByAppendingString:oldClassName];

const char * newClassName = [newName UTF8String];

b.定義一個(gè)類

Class MyClass = objc_allocateClassPair([self class], newClassName, 0);

c.添加setName方法---->也就是重寫方法

class_addMethod(MyClass, @selector(setName:), (IMP)setName, "v@:@");

d.注冊該類

objc_registerClassPair(MyClass);

e.修改被觀察者的isa指針,指向自定義的類

object_setClass(self, MyClass);

f.動(dòng)態(tài)綁定屬性

objc_setAssociatedObject(self, (__bridge const void *)@"123", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);


3.實(shí)現(xiàn)setName重寫方法

void setName(id self,SEL _cmd,NSString * newName){

? ? ? ?//搞事情

}

a.保存當(dāng)前類型

id class = [self class];

b.指向父類

object_setClass(self, class_getSuperclass([self class]));

c.調(diào)用父類的setName方法

objc_msgSend(self, @selector(setName:),newName);

d.拿出觀察者

id observer = objc_getAssociatedObject(self, (__bridge const void *)@"123");

e.通知

objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",@{@"new":newName},nil);

f.改回子類

object_setClass(self, class);


小結(jié):

此時(shí)我們用runtime重寫KVO基本簡單實(shí)現(xiàn)了,那么我們接下來實(shí)驗(yàn)一下

示例代碼:

//添加

Dog * dog = [[Dog alloc]init];

[dog MBXB_addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

_dog = dog;

//實(shí)現(xiàn)

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{

? ? ? NSLog(@"%@===>YES成功了%@",change,_dog.name);

}

//點(diǎn)擊屏幕來測試:

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {

? ? ?static int i = 0;

? ? ? i++;

? ? ? _dog.name = [NSString stringWithFormat:@"%d",i];

}

點(diǎn)擊屏幕測試結(jié)果,是不是成功了呢??


最后為大家奉獻(xiàn)上本文的代碼連接,大家多多點(diǎn)贊哦demo,希望大家下載star



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末废恋,一起剝皮案震驚了整個(gè)濱河市命浴,隨后出現(xiàn)的幾起案子泰演,更是在濱河造成了極大的恐慌溉痢,老刑警劉巖磷蜀,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異般渡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)芙盘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門驯用,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人儒老,你說我怎么就攤上這事蝴乔。” “怎么了驮樊?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵薇正,是天一觀的道長片酝。 經(jīng)常有香客問我,道長挖腰,這世上最難降的妖魔是什么雕沿? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮猴仑,結(jié)果婚禮上审轮,老公的妹妹穿的比我還像新娘。我一直安慰自己宁脊,他們只是感情好断国,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著榆苞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霞捡。 梳的紋絲不亂的頭發(fā)上坐漏,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音碧信,去河邊找鬼赊琳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砰碴,可吹牛的內(nèi)容都是我干的躏筏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呈枉,長吁一口氣:“原來是場噩夢啊……” “哼趁尼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起猖辫,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤酥泞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后啃憎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芝囤,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年辛萍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悯姊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贩毕,死狀恐怖悯许,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耳幢,我是刑警寧澤岸晦,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布欧啤,位于F島的核電站,受9級(jí)特大地震影響启上,放射性物質(zhì)發(fā)生泄漏邢隧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一冈在、第九天 我趴在偏房一處隱蔽的房頂上張望倒慧。 院中可真熱鬧,春花似錦包券、人聲如沸纫谅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽付秕。三九已至,卻和暖如春侍郭,著一層夾襖步出監(jiān)牢的瞬間询吴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工亮元, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猛计,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓爆捞,卻偏偏與公主長得像奉瘤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煮甥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉盗温,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 1.單例的寫法 (instancetype)sharedInstance {static id sharedIns...
    sunny_王閱讀 412評(píng)論 0 0
  • http://www.reibang.com/p/0f1e8dc0812a
    奇董閱讀 328評(píng)論 0 0
  • 有時(shí)候人說你要努力點(diǎn),你努力了苛秕,沒被看到肌访,所以你不想努力了。這時(shí)又會(huì)有人告訴你不要放棄艇劫,你接著努力吼驶,還是沒結(jié)果,所...
    Claire_書蟲閱讀 219評(píng)論 1 1
  • A - Shortest path of the king CodeForces - 3A The king is...
    Nioge閱讀 147評(píng)論 0 0