KVO 實(shí)現(xiàn)原理
KVO即Key-Value Observing,它提供一種機(jī)制,當(dāng)指定的對(duì)象的屬性被修改后,則對(duì)象就會(huì)接受到通知。簡單的說就是每次指定的被觀察的對(duì)象的屬性被修改后,KVO就會(huì)自動(dòng)通知相應(yīng)的觀察者了。
KVO的原理
- 當(dāng)一個(gè)object有觀察者時(shí),動(dòng)態(tài)創(chuàng)建這個(gè)object的類的子類
- 對(duì)于每個(gè)被觀察的property,重寫其set方法
- 在重寫的set方法中調(diào)用- willChangeValueForKey:和- didChangeValueForKey:通知觀察者
- 當(dāng)一個(gè)property沒有觀察者時(shí),刪除重寫的方法
- 當(dāng)沒有observer觀察任何一個(gè)property時(shí),刪除動(dòng)態(tài)創(chuàng)建的子類
當(dāng)我們?cè)谔砑佑^察者的時(shí)候,打一個(gè)斷點(diǎn),在設(shè)置屬性的時(shí)候打一個(gè)斷點(diǎn)



發(fā)現(xiàn)對(duì)象P的isa指針居然變量了,指向的類也不是我們自己創(chuàng)建的,那也就說明是系統(tǒng)自己創(chuàng)建的,Person類的子類NSKVONotifying_Person,并且重寫了set方法。其實(shí),就是去判斷有沒有調(diào)用一個(gè)對(duì)象的set方法
現(xiàn)在我們就手動(dòng)的模擬下這種情況
首先我們需要?jiǎng)?chuàng)建一個(gè)NSObject的分類,創(chuàng)建自己添加觀察者的方法
@interface NSObject (KVO)
- (void)xf_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
#import "NSObject+KVO.h"
#import <objc/runtime.h>
#import "XFKVONotifying_Person.h"
@implementation NSObject (KVO)
- (void)xf_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context {
// 修改isa,改變當(dāng)前對(duì)象的類名
object_setClass(self, [XFKVONotifying_Person class]);
//添加關(guān)聯(lián),把觀察者保存到當(dāng)前對(duì)象里
objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
由于我們使用了運(yùn)行時(shí),所以別忘記導(dǎo)入 <objc/runtime.h>
我們還需要?jiǎng)?chuàng)建一個(gè) XFKVONotifying_Person類,并繼承于 Person
#import "Person.h"
@interface XFKVONotifying_Person : Person
@end
#import "XFKVONotifying_Person.h"
#import <objc/runtime.h>
@implementation XFKVONotifying_Person
-(void)setAge:(NSInteger)age {
[super setAge:age];
//取出觀察者,并通知觀察者屬性改變
id observer = objc_getAssociatedObject(self, @"observer");
[observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
@end
最后我們調(diào)用自己寫的方法:
[p xf_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
一樣可以觀察到屬性值的變化
總結(jié)
KVO底層實(shí)現(xiàn)原理:
- 動(dòng)態(tài)創(chuàng)建NSKVONotifying_Person,NSKVONotifying_Person是Person子類,做KVO
- 修改當(dāng)前對(duì)象的isa指針->NSKVONotifying_Person
- 只要調(diào)用對(duì)象的set,就會(huì)調(diào)用NSKVONotifying_Person的set方法
- 重寫NSKVONotifying_Person的set方法:
- [super set:]
- 通知觀察者,告訴你屬性改變