美文网首页
KVO知识点

KVO知识点

作者: ychen3022 | 来源:发表于2018-10-02 15:03 被阅读11次
1、kvo的简单使用

创建文件MJPerson类,添加属性age、height。

#import "ViewController.h"
#import "MJPerson.h"

@interface ViewController ()
@property(nonatomic,strong)MJPerson *person1;
@property(nonatomic,strong)MJPerson *person2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.person1 = [[MJPerson alloc] init];
    self.person1.age =10;
    self.person1.height=100;
    
    self.person2 = [[MJPerson alloc] init];
    self.person2.age = 9;
    self.person2.height = 90;
    
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
   
    //我们给person1加上kvo监听
    [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"haha"];
    [self.person1 addObserver:self forKeyPath:@"height" options:options context:nil];
    
      //我们不给person2加上kvo监听
//    [self.person2 addObserver:self forKeyPath:@"age" options:options context:nil];
//    [self.person2 addObserver:self forKeyPath:@"height" options:options context:nil];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //person1和person2的age属性都发生变化
    self.person1.age = 20;
    self.person2.age = 99;
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"监听到%@的属性%@发生了变化----%@",object,keyPath,change);
}

-(void)dealloc{
    //记得在适当的时候去除监听
    [self.person1 removeObserver:self forKeyPath:@"age"];
    [self.person1 removeObserver:self forKeyPath:@"height"];
    
   // [self.person2 removeObserver:self forKeyPath:@"age"];
   // [self.person2 removeObserver:self forKeyPath:@"height"];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end


=====================================================
打印结果为:
监听到<MJPerson: 0x17400d110>的属性age发生了变化----{
    kind = 1;
    new = 20;
    old = 10;
}

因为我们去掉了对person2的监听,所以不会有显示person2属性的改变,但是person1的属性age改变被监听了下来。字典change的内容表示改变内容。

2、探究KVO本质

先上example:
创建文件MJPerson类,添加属性age。

#import "ViewController.h"
#import "MJPerson.h"

@interface ViewController ()
@property(nonatomic,strong)MJPerson *person1;
@property(nonatomic,strong)MJPerson *person2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.person1 = [[MJPerson alloc] init];
    self.person1.age =10;
    
    self.person2 = [[MJPerson alloc] init];
    self.person2.age = 9;

    //给person1加上kvo监听
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
    [self.person1 addObserver:self forKeyPath:@"age" options:options context:nil];
}


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//   因为使用了KVO监听self.person1,
//   所以,runtime动态创建一个新的类NSKVONotifying_MJPerson,这个类应该是MJPerson的子类
//   self.person1.isa = NSKVONotifying_MJPerson
    [self.person1 setAge:20];
    
    
//   self.person2.isa = MJPerson
    [self.person2 setAge:99];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"监听到%@的属性%@发生了变化----%@",object,keyPath,change);
}

-(void)dealloc{
    [self.person1 removeObserver:self forKeyPath:@"age"];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

原理图如下:


31538461242_.pic.jpg 41538461242_.pic.jpg

伪代码如下:

@implementation NSKVONotifying_MJPerson

-(void)setAge:(int)age{
    _NSSetIntValueAndNotify();
}

//伪代码
void _NSSetIntValueAndNotify(){
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

-(void)didChangeValueForKey:(NSString *)key{
    [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
3、总结:

<1>KVO的本质是什么?
在程序运行中,利用runtime动态生成一个子类NSKVONotifying_MJPerson(该类是MJPerson的子类)且让对象的isa指向这个全新的子类。通过重写该子类set方法,使得修改对象的属性时,会调用foundation的_NSSetXXXValueAndNotify函数,

  • willChangeValueForKey
  • 父类原来的set方法
  • didChangeValueForKey
    继而触发监听器

<2>如何手动触发KVO?
本来是应该通过改变对象属性值来触发KVO的。如果非要手动触发,可以调用willChangeValueForKey和didChangeValueForKey方法,这样属性值没有发生变化,还能触发KVO监听。

<3>.直接修改成员变量会触发KVO吗?
只有通过触发set方法才会触发KVO,如果使用self.person1->_age这种方法来直接修改对象属性的话,是不会触发对象的set方法的,所以不会触发KVO监听。

相关文章

  • iOS 底层探索之KVO

    KVO是Objective-C中的键值监听策略,本篇能学习到以下知识点1、KVO的使用方法大全2、KVO的底层如何...

  • iOS知识体系总结-KVO&KVC

    注意:更新内容会同步到GitHub iOSWiki-知识体系总结 总结-KVO&KVC iOS知识点/KVO&KV...

  • KVO机制详解

    Key-Value Observing机制 知识点介绍 Key-Value Observing (简写为KVO):...

  • KVO知识点

    1、kvo的简单使用 创建文件MJPerson类,添加属性age、height。 因为我们去掉了对person2的...

  • iOS KVC 和KVO 老生常谈系列(一)

    首先,给大家讲一下这两个基础知识点的重点。 一、KVC与KVO 二、KVC的使用方式 三、KVO的使用方式

  • 2.RAC解析 - 自定义KVO

    知识点概述 1.KVO实现原理2.runtime使用 目的 给NSObject添加一个Category,用于给实例...

  • iOS原理篇(一): KVO实现原理

    KVO实现原理 什么是 KVO KVO 基本使用 KVO 的本质 总结 一 、 什么是KVO KVO(Key-Va...

  • kvo、kvc知识点总结

    KVC和KVO 一、摘要 *1 KVO,即:Key-Value-Observing,它提供一种机制,当指定的对象的...

  • 查漏补缺——在WeiboDemo开发以后

    本周着重掌握以下知识点: AppDelegate相关函数 ARC下数据的关键词的修饰问题 KVO 键值观察者 No...

  • 04. KVO使用,原理,本质

    问题 KVO日常使用 KVO原理(KVO本质是什么) 如何手动触发KVO 直接修改成员变量会触发KVO吗 KVO图...

网友评论

      本文标题:KVO知识点

      本文链接:https://www.haomeiwen.com/subject/oirfnftx.html