什么是KVO
- KVO俗稱“鍵值監(jiān)聽”典尾,用來監(jiān)聽某個(gè)對(duì)象屬性值的改變
KVO的使用
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [[GMPerson alloc] init];
self.person1.height = 160;
self.person1.name = @"GM";
NSKeyValueObservingOptions option = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
/**
* Observer: 觀察者
* forKeyPath: 需要觀察的屬性
* options: 有4個(gè)值 分別是:
* NSKeyValueObservingOptionNew 更改后的值篙顺,提供給處理方法
* NSKeyValueObservingOptionOld 更改前的值滑燃,提供給處理方法
* NSKeyValueObservingOptionInitial 把初始化的值提供給處理方法头镊,一旦注冊(cè)毛好,立馬就會(huì)調(diào)用一次。通常它會(huì)帶有新值躏救,而不會(huì)帶有舊值
* NSKeyValueObservingOptionPrior 分2次調(diào)用唯笙。在值改變之前和值改變之后
* context: 可以帶入一些自定義參數(shù)
*/
[self.person1 addObserver:self forKeyPath:@"name" options:option context:@"123"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// self.person1.height = 175;
self.person1.name = @"GMhaha";
}
- (void)dealloc{
[self.person1 removeObserver:self forKeyPath:@"name"];
}
/** 監(jiān)聽當(dāng)前對(duì)象屬性值發(fā)生改變時(shí)會(huì)調(diào)用 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"監(jiān)聽到了%@的屬性值%@ 改變了 - %@ 自定義參數(shù) - %@",object,keyPath,change,context);
}
KVO 本質(zhì)
在給某個(gè)對(duì)象添加KVO監(jiān)聽時(shí),程序會(huì)使用Runtime動(dòng)態(tài)創(chuàng)建一個(gè)類盒使,例如:以上代碼崩掘,我們要給 self.person1 這個(gè)對(duì)象添加KVO,在注冊(cè)監(jiān)聽時(shí)少办,系統(tǒng)會(huì)使用Runtime動(dòng)態(tài)的創(chuàng)建一個(gè)GMPerson的子類 NSKVONotifying_GMPerson苞慢。self.person1 這個(gè)對(duì)象的isa指針,指向 NSKVONotifying_GMPerson 這個(gè)子類英妓,在我們改變person1里面的屬性值時(shí)挽放,會(huì)調(diào)用 NSKVONotifying_GMPerson 這個(gè)子類里的 set方法。NSKVONotifying_GMPerson 類里的set方法會(huì)調(diào)用Foundation框架里的 _NSSetIntValueAndNotify(根據(jù)具體屬性類型調(diào)用蔓纠。比如:float 類型會(huì)調(diào)用_NSSetFloatValueAndNotify) 這個(gè)C語言方法 這個(gè)方法里面實(shí)際上又調(diào)用了 willChangeValueForKey辑畦、set方法、didChangeValueForKey 方法腿倚,didChangeValueForKey方法里實(shí)際上是調(diào)用了通知監(jiān)聽器的方法纯出。
NSKVONotifying_GMPerson 類具體實(shí)現(xiàn)的偽代碼如下:
//
// NSKVONotifying_GMPerson.m
// KVO
//
// Created by G_M on 2022/2/10.
//
#import "NSKVONotifying_GMPerson.h"
@implementation NSKVONotifying_GMPerson
- (void)setHeight:(int)height{
_NSSetIntValueAndNotify();
}
/** 偽代碼,具體實(shí)現(xiàn)蘋果未開源 */
void _NSSetIntValueAndNotify(){
[self willChangeValueForKey:@"height"];
[super setHeight:height];
[self didChangeValueForKey:@"height"];
}
- (void)didChangeValueForKey:(NSString *)key{
/** 通知監(jiān)聽器敷燎,某屬性的key值發(fā)生了改變 */
[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
這些都是蘋果動(dòng)態(tài)生成的暂筝,并不需要我們自己編寫,寫出來只是為了幫助理解KVO的本質(zhì)懈叹。