iOS程序员首页投稿(暂停使用,暂停投稿)程序员

KVO简单解析

2016-07-16  本文已影响219人  过过过客
#import "ViewController.h"
#import "LJModel.h"

@interface ViewController ()

@property (strong, nonatomic) LJModel *model;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    LJModel *model = [[LJModel alloc]init];
    
    // 赋值
    _model = model;
    
    // 添加观察者 ,监听model的 name 属性的值的 改变
    [model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:@"ViewController"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    
    NSLog(@"%@",_model.name);
    
    // 点击三次的打印结果为:
    /*
     2016-07-12 12:56:31.453 answerDemo[2584:753037] 小强 1 号
     2016-07-12 12:56:40.509 answerDemo[2584:753037] 小强 2 号
     2016-07-12 12:56:42.195 answerDemo[2584:753037] 小强 3 号
     */
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 用于判断每次点击,都给name属性赋值
    static int i = 0;
    
    i ++;
    
    // 通过set方法 给model的name赋值
    _model.name = [NSString stringWithFormat:@"小强 %d 号",i];
    
}

@end

这个是如何实现的呢?

那我们现在来做这样一件事情:

#import <Foundation/Foundation.h>

@interface LJModel : NSObject

{
    @public
    NSString *_name;
}

@end
    // 直接访问成员变量进行赋值
    _model -> _name = [NSString stringWithFormat:@"小强 %d 号",i];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    
    NSLog(@"%@",_model -> _name);

}
isa指向LJModel.png isa指向NSKVONotifying_LJModel.png

到这里之后,我们尝试的写了一下,简单的仿照系统,自己搞个可以监听name的值得变化的方法:

@interface NSObject(NSKeyValueObserverRegistration)
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

@end
#import "NSObject+Extension.h"
#import <objc/runtime.h>
#import "LJSubModel.h"

@implementation NSObject (Extension)

- (void)lj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
    
    
    // 将当前对象的指针指向观察者
    object_setClass(self, [LJSubModel class]);

    // 给当前对象添加一个观察者(ViewController)的属性
    objc_setAssociatedObject(self, "observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

@end

然后看一下subModelsetName方法的实现:

#import "LJSubModel.h"
#import <objc/runtime.h>

@implementation LJSubModel

- (void)setName:(NSString *)name {
    [super setName:name];
    
    // 获取观察者
    id observer = objc_getAssociatedObject(self, @"observer");
    
    // 通知观察者调用方法
    [observer observeValueForKeyPath:@"name" ofObject:observer change:nil context:nil];
}

@end

最后调用自己的方法实现监听:

    // 添加观察者 ,监听model的 name 属性的值的 改变
    [model lj_addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
isa指向SubModel.png

这样,用我们自己的方法,也可以实现简单的KVO了

KVO很强大,有很多值的我们探究的地方,这里只是简单的介绍了一下KVO的实现机制,希望能帮到大家

demo传送门:https://github.com/lauding/answerDemo

另外附上一篇个人觉得比较好的介绍KVO的实现的博客:http://www.cocoachina.com/ios/20150313/11321.html

对我的Demo有什么疑问或者建议,欢迎留言

上一篇 下一篇

猜你喜欢

热点阅读