iOS底層探究—KVO

KVO的全稱是Key-Value Observing,俗稱“鍵值監(jiān)聽”,可以用于監(jiān)聽某個(gè)對(duì)象屬性值的改變


1.KVO使用方法

1. 添加監(jiān)聽:

addObserver:forKeyPath:options:context:

self.person = [[Person alloc] init];
self.person.age = 1;

NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person addObserver:self forKeyPath:@"age" options:options context:@"123"];

2. 監(jiān)聽回調(diào):

當(dāng)監(jiān)聽對(duì)象的屬性值發(fā)生改變時(shí)肺稀,就會(huì)調(diào)用observeValueForKeyPath:ofObject:change: context:

// 當(dāng)監(jiān)聽對(duì)象的屬性值發(fā)生改變時(shí)赘艳,就會(huì)調(diào)用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"監(jiān)聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}

2.探索KVO的本質(zhì)

@interface ViewController ()
@property (strong, nonatomic) Person *person1;
@property (strong, nonatomic) Person *person2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.person1 = [[Person alloc] init];
    self.person1.age = 1;
    
    self.person2 = [[Person alloc] init];
    self.person2.age = 2;
    
    // 給person1對(duì)象添加KVO監(jiān)聽
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
    [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//    self.person1.age = 21;
//    self.person2.age = 22;
    
    // NSKVONotifying_Person是使用Runtime動(dòng)態(tài)創(chuàng)建的一個(gè)類,是Person的子類
    
    // self.person1.isa == NSKVONotifying_Person
    [self.person1 setAge:21];
    
    // self.person2.isa = Person
    [self.person2 setAge:22];
}

- (void)dealloc {
    [self.person1 removeObserver:self forKeyPath:@"age"];
}
// 當(dāng)監(jiān)聽對(duì)象的屬性值發(fā)生改變時(shí)辆脸,就會(huì)調(diào)用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"監(jiān)聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}

@end

在上面的代碼中但校,僅僅對(duì)person1添加了KVO監(jiān)聽,通過(guò)斷點(diǎn)分別獲取到person1isa->NSKVONotifying_Person,
person2isa->Person

image

當(dāng)實(shí)例對(duì)象未使用KVO監(jiān)聽,person1isa指向的類對(duì)象為Person啡氢,結(jié)構(gòu)如下:
未使用KVO監(jiān)聽

當(dāng)實(shí)例對(duì)象添加了KVO監(jiān)聽状囱,person1isa指向的類對(duì)象就變成了另外一個(gè)NSKVONotifying_Person,而NSKVONotifying_Person類對(duì)象的superclass指針才指向了Person倘是。
NSKVONotifying_Person是使用Runtime動(dòng)態(tài)創(chuàng)建的一個(gè)類亭枷,是Person的子類,結(jié)構(gòu)如下:

使用KVO監(jiān)聽

當(dāng)調(diào)用setAge:方法的時(shí)候搀崭,通過(guò)查看IMP地址叨粘,實(shí)際上調(diào)用的是Foundation框架里的_NSSetIntValueAndNotify函數(shù),

調(diào)用過(guò)程如下(偽代碼):

- (void)setAge:(int)age
{
    _NSSetIntValueAndNotify();
}

// 偽代碼
void _NSSetIntValueAndNotify()
{
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

- (void)didChangeValueForKey:(NSString *)key
{
    // 通知監(jiān)聽器门坷,某某屬性值發(fā)生了改變
    [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}

_NSSetIntValueAndNotify函數(shù)里面先是調(diào)用了[self willChangeValueForKey:@"age"] -> [super setAge:age]->[self didChangeValueForKey:@"age"];,然后在didChangeValueForKey:里面通過(guò)監(jiān)聽對(duì)象[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil]


3.查看_NSSet*AndNotify的存在

根據(jù)對(duì)監(jiān)聽對(duì)象類型的不同宣鄙,生成的方法也不同


4._NSSet*ValueAndNotify的內(nèi)部實(shí)現(xiàn)

NSSet*ValueAndNotify的內(nèi)部實(shí)現(xiàn)
  • 調(diào)用willChangeValueForKey:
  • 調(diào)用原來(lái)的setter實(shí)現(xiàn)
  • 調(diào)用didChangeValueForKey:
  • didChangeValueForKey:內(nèi)部會(huì)調(diào)用observer的observeValueForKeyPath:ofObject:change:context:方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市默蚌,隨后出現(xiàn)的幾起案子冻晤,更是在濱河造成了極大的恐慌,老刑警劉巖绸吸,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼻弧,死亡現(xiàn)場(chǎng)離奇詭異设江,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)攘轩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門叉存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人度帮,你說(shuō)我怎么就攤上這事歼捏。” “怎么了笨篷?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵瞳秽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我率翅,道長(zhǎng)练俐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任冕臭,我火速辦了婚禮腺晾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辜贵。我一直安慰自己悯蝉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布托慨。 她就那樣靜靜地躺著泉粉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪榴芳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天跺撼,我揣著相機(jī)與錄音窟感,去河邊找鬼。 笑死歉井,一個(gè)胖子當(dāng)著我的面吹牛柿祈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哩至,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼躏嚎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了菩貌?” 一聲冷哼從身側(cè)響起卢佣,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎箭阶,沒(méi)想到半個(gè)月后虚茶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體戈鲁,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年嘹叫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婆殿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罩扇,死狀恐怖婆芦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喂饥,我是刑警寧澤消约,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站仰泻,受9級(jí)特大地震影響荆陆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜集侯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一被啼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棠枉,春花似錦浓体、人聲如沸崇摄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)廉羔。三九已至步悠,卻和暖如春和敬,著一層夾襖步出監(jiān)牢的瞬間诀诊,已是汗流浹背掀泳。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工月幌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碍讯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓扯躺,卻偏偏與公主長(zhǎng)得像捉兴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子录语,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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

  • 廢話不多說(shuō)先來(lái)幾個(gè)面試題: 一倍啥,iOS用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO?(KVO的本質(zhì)是什么澎埠?)二虽缕,如何手動(dòng)觸發(fā)K...
    程序小胖閱讀 288評(píng)論 0 0
  • 面試題引發(fā)的思考: Q: iOS用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO?即KVO的本質(zhì)是什么失暂? 利用RuntimeAPI...
    hazydream閱讀 605評(píng)論 0 0
  • 1. KVO 一.KVO原理的使用與證明 我們?cè)陂_發(fā)的過(guò)程中經(jīng)常使用KVO和KVC,但是我們并不了解其底層原理和功...
    周灬閱讀 845評(píng)論 0 9
  • KVO的全稱是Key-Value-Observing彼宠,俗稱“鍵值監(jiān)聽”鳄虱,可以用于監(jiān)聽某個(gè)對(duì)象屬性值的改變。 1凭峡、K...
    毅想天開的小毅閱讀 487評(píng)論 1 1
  • KVO的全稱是Key-Value Observing拙已,俗稱鍵值監(jiān)聽,可以用于監(jiān)聽某個(gè)對(duì)象屬性值的改變摧冀。下面我們來(lái)了...
    Goose的小黃花閱讀 467評(píng)論 0 2