一放仗、回顧系統(tǒng)的KVO是怎么實(shí)現(xiàn)監(jiān)聽的
#1. 實(shí)例化一個(gè)類
Person *person = [[Person alloc] init];
person.age = 11;
#2. 開始監(jiān)聽
[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
#3. 值改變時(shí)(age = 111)润绎,監(jiān)聽執(zhí)行的方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"person 的值變了:%d",_person.age);
}
我們既然要手動(dòng)寫一個(gè)KVO,那么就要自己寫一個(gè)API诞挨,讓person調(diào)嘍莉撇,還有一個(gè)就是值發(fā)生變化,也會(huì)調(diào)一個(gè)我們自己的API嘍惶傻,例如:ml_observer棍郎,具體請看下面
二、手動(dòng)做咱們自己的KVO
****核心步驟如下:****
一)银室、生成一個(gè)Person類的派生類 Person_KVO涂佃。
二)静秆、使當(dāng)前對(duì)象的isa指向新的派生類,就會(huì)調(diào)用派生類的set方法巡李。
三)抚笔、重寫Person_KVO的setAge方法,在set方法中拿到觀察者(使用運(yùn)行時(shí)關(guān)聯(lián)觀察者這個(gè)屬性)侨拦。
四)殊橙、每次重寫setAge方法,都調(diào)用觀察者的ml_observeValueForKeyPath方法狱从。實(shí)現(xiàn)時(shí)刻監(jiān)聽膨蛮。
****代碼如下:****
ViewController.h
Person *person = [[Person alloc] init];
_person = person;
#調(diào)用手寫KVO開始監(jiān)聽方法
[person ml_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
# 監(jiān)聽方法 (驗(yàn)證手寫KVO是否成功)
- (void)ml_observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"person 的值變了:%d",_person.age);
}
NSObject+KVO.h
- (void)ml_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
//修改isa指針,就是把`當(dāng)前對(duì)象`指向一個(gè)`新類`
// Person's isa -> Person_KVO
// Class object_setClass(id obj, Class cls)
//使當(dāng)前對(duì)象的isa指向新的派生類(Person_KVO)季研,就會(huì)調(diào)用派生類的set方法
object_setClass(self, [Person_KVO class]);
//給對(duì)象綁定觀察者對(duì)象
objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Person_KVO.h
-(void)setAge:(int)age{ [super setAge:age]; //修改了子類的值后敞葛,父類的值也修改了
//調(diào)用KVO
//獲取觀察者
id observer = objc_getAssociatedObject(self, @"observer");
//調(diào)用觀察者的方法
//就是驗(yàn)證手寫KVO的方法 observer其實(shí)就是VC
[observer ml_observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
PS:該代碼僅僅是模擬KVO的底層實(shí)現(xiàn)流程,主要注重流程与涡,具體的什么參數(shù)如觀察新值惹谐、舊值,沒有做驼卖,有強(qiáng)迫癥的朋友有興趣可以設(shè)置個(gè)枚舉即可氨肌!
三、流程圖