1、KVO簡單介紹
KVO(Key Value Observing)鍵值監(jiān)聽,屬于蘋果官方API。
作用:iOS開發(fā)中通常將代碼分為數(shù)據(jù)模型和試圖控件,數(shù)據(jù)模型維護程序的狀態(tài)數(shù)據(jù),試圖控件將數(shù)據(jù)模型中的數(shù)據(jù)展示出來。而KVO能監(jiān)聽當(dāng)數(shù)據(jù)模型發(fā)生改變時,及時通知試圖控件動態(tài)將改變的數(shù)據(jù)顯示出來。 注意:只有通過setter方法改變的屬性值,才能被KVO監(jiān)聽到,才能觸發(fā)observeValueForKeyPath:ofObject:change:context:回調(diào)方法
KVO的使用: 1.注冊需要觀察的對象的屬性addObserver:forKeyPath:options:context: 2.實現(xiàn)observeValueForKeyPath:ofObject:change:context:方法,這個方法當(dāng)觀察的屬性變化時會自動調(diào)用 3.取消注冊觀察removeObserver:forKeyPath:context:
- (void)viewDidLoad { [super viewDidLoad]; self.stu = [[Student alloc] init]; // 添加觀察者 // observer:觀察者 keyPath:想要監(jiān)聽的屬性名 options:枚舉 回調(diào)時可以獲取改變前后的值 content:上下文 [self.stu addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];}// 屬性發(fā)生改變時的回調(diào)- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ // keyPath:屬性名 change:改變前后的屬性值 content:上下文 NSLog(@"%@", change[@"new"]);}// 釋放觀察者- (void)dealloc{ [self.stu removeObserver:self forKeyPath:@"age"];}2、KVO底層實現(xiàn)(記錄自小馬哥視頻)
當(dāng)KVO被觸發(fā)時 1>首先系統(tǒng)會自動創(chuàng)建NSKVONotifying_Student類(這里以Student為例), NSKVONotifying_Student是Student的子類 2>修改當(dāng)前對象(student)的isa指針,指向NSKVONotifying_Student 3>只要調(diào)用對象的setter方法,就會調(diào)用NSKVONotifying_Student的setter方法 4>重寫NSKVONotifying_Student的setter方法:[super set:],通知觀察者對象的屬性值發(fā)生改變
下面我們來自己實現(xiàn)KVO,以便更好的理解KVO的底層實現(xiàn)過程。 1>系統(tǒng)KVO是基于NSObject,所以我們可以創(chuàng)建一個NSObject的分類NSObject+KVO NSObject+KVO.h文件
#import <Foundation/Foundation.h>@interface NSObject (KVO)- (void)zhaoName_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;@endNSObject+KVO.m文件
#import "NSObject+KVO.h"#import <objc/runtime.h>#import "ZKVONotifying_Student.h"@implementation NSObject (KVO)- (void)zhaoName_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{ // 修改isa指針 本質(zhì)是改變當(dāng)前對象的類名 object_setClass(self, [ZKVONotifying_Student class]); // 保存觀察者 即動態(tài)添加屬性 // object:給哪個對象添加屬性 key:屬性名 value:屬性值 policy:關(guān)聯(lián)策略 objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end2>重寫子類NSKVONotifying_Student的setter方法,通知觀察者 NSKVONotifying_Student.m文件
#import "ZKVONotifying_Student.h"#import <objc/runtime.h>@implementation ZKVONotifying_Student- (void)setAge:(NSUInteger)age{ [super setAge:age]; // 獲取保存的觀察者 id observer = objc_getAssociatedObject(self, @"observer"); // 通知 // 注意這里change傳nil,則在回調(diào)時change為空 [observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];}@end這樣調(diào)用我們自己實現(xiàn)的KVO也能實現(xiàn)屬性改變的監(jiān)聽
[self.stu zhaoName_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];新聞熱點
疑難解答