iOS- KVO的底层实现/响应式编程

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 
@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 
@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 
@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 
#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 *)change context:(void *)context{
    NSLog(@"%d",_p.age);

}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    _p.age++;
    //    _p->_age ++;
}

你可能感兴趣的:(iOS- KVO的底层实现/响应式编程)