■ 核心:当一个类有观察者时,生成一个中间类,把它的
isa
指向中间类。
(生成中间类就方便去重写它的set
方法。KVO
是当你调用了set
方法时它才会被触发。我重新生成set
方法,里面也添加进去发送通知的方法。当我去调用set
方法时,就会去触发它的KVO
机制)
原理:
■ 当一个
object
有观察者时,动态创建这个object
的类的子类■ 对于每个被观察的
property
,去重写其set
方法■ 在重写的set方法中调用
-willChangeValueForKey:
和-didChangeValueForKey:
手动控制发送通知的时机,需要的核心方法
■ -(
void
)willChangeValueForKey:(NSString
*)key■ -(void)didChangeValueForKey:(NSString *)key
■ +(
BOOL
)automaticallyNotifiesObserverForKey:(NSString
*)key //通过这个方法去判定key
的情况,不让系统自动去发送。我自己手动控制发送通知,可以返回一个NO
CFPerson.h
#import <Foundation/Foundation.h>
@interface CFPerson : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *age;
- (void)setInfo:(NSDictionary *)info;
@end
CFPerson.m
#import "CFPerson.h"
@implementation CFPerson
- (void)setName:(NSString *)name
{
if(_name!=name){
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
}
- (void)setInfo:(NSDictionary *)info
{
[self willChangeValueForKey:@"age"];
[self willChangeValueForKey:@"name"];
_name = info[@"name"];
_age = info[@"age"];
[self didChangeValueForKey:@"name"];
[self didChangeValueForKey:@"age"];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
if([key isEqualToString:@"name"]||[key isEqualToString:@"age"])
{
return NO;
}else
{
return [super automaticallyNotifiesObserversForKey:key];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"属性%@改变之前的值为:%@",keyPath,change[NSKeyValueChangeOldKey]);
NSLog(@"属性%@改变之后的值为:%@",keyPath,change[NSKeyValueChangeNewKey]);
}
@end
main.m
#import <Foundation/Foundation.h>
#import "CFPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFPerson *person = [[CFPerson alloc]init];
person.name = @"lilei";
//添加observer
[person addObserver:person forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[person addObserver:person forKeyPath:@"age" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
// person.name = @"zhangsan";
// //手动发送通知
// [person willChangeValueForKey:@"name"];
// person.name = @"lilei";
// [person didChangeValueForKey:@"name"];
//调用重写的setter方法
// person.name = @"zhangsan";
//一个操作发送两个通知
[person setInfo:@{@"name":@"wanger",@"age":@"20"}];
}
return 0;
}
2019-03-13 15:43:52.037056+0800 手动调用KVO[14200:1509438] 属性name改变之前的值为:lilei
2019-03-13 15:43:52.037277+0800 手动调用KVO[14200:1509438] 属性name改变之后的值为:wanger
2019-03-13 15:43:52.037328+0800 手动调用KVO[14200:1509438] 属性age改变之前的值为:<null>
2019-03-13 15:43:52.037347+0800 手动调用KVO[14200:1509438] 属性age改变之后的值为:20