KVO底层实现--写一个自己的KVO

KVO底层原理  

Person * p =[[Person alloc] init];

[p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

p这个对象一旦添加观察者后,系统会将这个Person这个类的isa指针修改为 NSKVONotifying_Person,NSKVONotifying_Person 这个类是Person类的子类, 这样每次访问p其实访问NSKVONotifying_Person这样类名的p,然后系统会重写p age属性的set方法.在set方法里面调用

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context这个方法.完了再调用super 方法.



知道原理,我们就可以自己来写一个自己的KVO验证一下


模仿系统给NSObejct添加一个分类,具有添加自己的观察者的能力

//

//  NSObject+MY_KVO.h

//  arc

//

//  Created by SGQ on 16/6/2.

//  Copyright © 2016 GQ. All rights reserved.

//


#import <Foundation/Foundation.h>


@interface NSObject (MY_KVO)

- (void)My_addObserver:(NSObject *_Nonnull)observer forKeyPath:(NSString *_Nonnull)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

@end


实现

//

//  NSObject+MY_KVO.m

//  arc

//

//  Created by SGQ on 16/6/2.

//  Copyright © 2016 GQ. All rights reserved.

//


#import "NSObject+MY_KVO.h"

#import "MY_KVONotifying_Person.h"

#import <objc/runtime.h>


@implementation NSObject (MY_KVO)


-(void)My_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{

    // 修改isa指针(runtime) 系统的MY_KVONotifying_Person这个类是动态生成的,我们直接手动创建


    object_setClass(self, [MY_KVONotifying_Person class]);

   // 给对象动态添加属性,之前文章介绍过了.目的是保存observer,好在set方法里面拿到,调用

My_addObserver:forKeyPath:options:context:这个方法


    objc_setAssociatedObject(self, (__bridge const void *)(keyPath), observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

@end


二,重写MY_KVONotifying_Person set方法

//

//  MY_KVONotifying_Person.m

//  arc

//

//  Created by SGQ on 16/6/2.

//  Copyright © 2016 GQ. All rights reserved.

//


#import "MY_KVONotifying_Person.h"

#import "NSObject+MY_KVO.h"

#import <objc/runtime.h>

@implementation MY_KVONotifying_Person

- (void)setAge:(int)age{

   id observer = objc_getAssociatedObject(self, @"age");

    if (observer && [observer respondsToSelector:@selector(My_addObserver:forKeyPath:options:context:)]) {

        [observer My_addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

    }

    [super setAge:age];

}

@end


三.使用一下

#import "ViewController.h"

#import "Person.h"

#import "NSObject+MY_KVO.h"

@interface ViewController ()


@property (nonatomic,strong)Person * p;

@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

   

    Person * p =[[Person alloc] init];

    [p My_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

    

    _p= p;

}

- (void)My_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{

    NSLog(@"age++ 自己的KVO");

}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

     _p.age ++ ;

}

我们可以看到打印


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值