KVO 是 Objective-C 对观察者设计模式的一种实现
KVO基本原理
当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法随后负责通知观察对象属性的改变状况。
KVO底层实现原理
1.动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO
2.修改当前对象的isa指针->NSKVONotifying_Person
3.只要调用对象的set,就会调用NSKVONotifying_Person的set方法
4.重写NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
下面我们来实现KVO和自定义KVO
Person类
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, assign) int age;
@end
#import "Person.h"
@implementation Person
@end
派生类
#import "Person.h"
@interface LPKVONotifying_Person : Person
@end
#import "LPKVONotifying_Person.h"
#import <objc/runtime.h>
@implementation LPKVONotifying_Person
- (void)setAge:(int)age
{
[super setAge:age];
// 通知观察者,属性改变
id observer = objc_getAssociatedObject(self, @"observer");
[observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
@end
添加KVO分类
#import <Foundation/Foundation.h>
@interface NSObject (KVO)
- (void)lp_addObserver:(NSObject *_Nullable)observer forKeyPath:(NSString *_Nullable)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
#import "NSObject+KVO.h"
#import <objc/runtime.h>
#import "LPKVONotifying_Person.h"
@implementation NSObject (KVO)
- (void)lp_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
// 1.动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO
// 2.修改当前对象的isa指针->NSKVONotifying_Person
// 3.只要调用对象的set,就会调用NSKVONotifying_Person的set方法
// 4.重写NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
// 修改isa,本质就是改变当前对象的类名
object_setClass(self, [LPKVONotifying_Person class]);
// 把观察者保存到当前对象里
// 添加关联
// id object:给哪个对象添加关联属性
// key:属性名
// value:关联值
objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
调用
#import "KVOViewController.h"
#import "Person.h"
#import "LPKVONotifying_Person.h"
@interface KVOViewController ()
@property (nonatomic, strong) Person *p;
@end
@implementation KVOViewController
- (void)viewDidLoad {
[super viewDidLoad];
// KVO
//[self NSKVO];
// 仿写KVO
[self LPKVO];
}
- (void)NSKVO
{
Person *person = [[Person alloc]init];
_p = person;
[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)LPKVO
{
Person *person = [[Person alloc]init];
_p = person;
[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
// 只要p的age属性一改变,就会调用观察者的observeValueForKeyPath
// KVO底层实现:
// 1.动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO
// 2.修改当前对象的isa指针->NSKVONotifying_Person
// 3.只要调用对象的set,就会调用NSKVONotifying_Person的set方法
// 4.重写NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
// 就是去判断有没有调用一个对象的set方法
}
// 监听的属性只要一改变就调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%d",_p.age);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
_p.age++;
// _p->_age ++;
}