KVO 全稱Key-Value Observing,俗稱"鍵值監(jiān)聽"气笙,可以用于監(jiān)聽某個(gè)對(duì)象屬性值的改變
KVO 基本使用方法
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [[MJPerson alloc] init];
self.person1.age = 1;
self.person1.height = 11;
self.person2 = [[MJPerson alloc] init];
self.person2.age = 2;
self.person2.height = 22;
// 給person1對(duì)象添加KVO監(jiān)聽
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
[self.person1 addObserver:self forKeyPath:@"height" options:options context:@"456"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person1.age = 20;
self.person2.age = 20;
self.person1.height = 30;
self.person2.height = 30;
}
// 當(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);
}
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
[self.person1 removeObserver:self forKeyPath:@"height"];
}
從上述代碼可看出谭期,alloc出來的person1 與 person2 實(shí)例對(duì)象吧凉,在點(diǎn)擊屏幕的時(shí)候,只監(jiān)測(cè)到了person1對(duì)象值的變化鸳劳,沒有監(jiān)測(cè)到person2對(duì)象的變化?從代碼的角度考慮是因?yàn)閜erson2對(duì)象沒有添加KVO涵紊,那么添加了KVO之后摸柄,person1實(shí)例對(duì)象在內(nèi)存中發(fā)生了什么變換?
先看person2實(shí)例對(duì)象的內(nèi)存調(diào)用圖
person1實(shí)例對(duì)象使用了KVO 那么它的內(nèi)存調(diào)用圖如下
OC在運(yùn)行時(shí)的時(shí)候自動(dòng)生成了一個(gè)NSKVONotifying_MJPerson 類對(duì)象作為MJPerson類對(duì)象的子類對(duì)象,通過底層C _NSSetIntValueAndNotify方法 重寫了setAge:方法宇挫,進(jìn)而實(shí)現(xiàn)KVO的過程
以下可理解為實(shí)現(xiàn)該過程的偽代碼
#import "MJPerson.h"
@interface NSKVONotifying_MJPerson : MJPerson
@end
#import "NSKVONotifying_MJPerson.h"
@implementation NSKVONotifying_MJPerson
- (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];
}
@end
總結(jié)如圖所示
從上圖可以看出來如果添加了KVO又不想修改屬性值,那怎么主動(dòng)調(diào)用監(jiān)聽方法呢橡疼,即可以調(diào)用以下兩個(gè)方法主動(dòng)去觸發(fā)監(jiān)聽方法
[self willChangeValueForKey:@"age"];
[self didChangeValueForKey:@"age"];
KVC 全稱Key-Value Coding援所,俗稱"鍵值編碼",可以通過一個(gè)Key來訪問某個(gè)屬性
KVC常用方法 (經(jīng)常用到欣除,用法不做過多解釋)
//賦值
-(void)setValue:(id)value forKeyPath:(NSString *)keyPath;
-(void)setValue:(id)value forKey:(NSString *)key;
//取值
-(id)valueForKeyPath:(NSSting *)keyPath;
-(id)valueForKey:(NSSting *)key;
直接展示原理圖
賦值邏輯
取值邏輯
注意:賦值住拭,或 取值 都是有查找順序的
問題:KVC 修改屬性會(huì)觸發(fā)KVO么?
會(huì)觸發(fā)KVO的
因?yàn)镵VC內(nèi)部會(huì)實(shí)現(xiàn)willChangeValueForKey: didChangeValueForKey: 方法 具體筆記不再論證
下篇文章鏈接