当前位置: 首页 > news >正文

KVO知识点

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.
}
复制代码

原理图如下:

伪代码如下:

@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监听。

转载于:https://juejin.im/post/5bb473255188255c7f5ec3c0

相关文章:

  • Selenium 对窗口对HTML的操作举例
  • 设计模式(十五)[结构模式] 合成模式(Composite)
  • Spring框架5.1将提供对Java 11的支持
  • Uber开源Marmaray:基于Hadoop的通用数据摄取和分散框架
  • LeetCode - 141. Linked List Cycle
  • kubernetes[2]-Pod
  • @jsonView过滤属性
  • vmware创建centos虚拟机
  • 福大软工1816 · 第六次作业 - 团队选题报告
  • 尝试解决微信小程序分页最后setData数据太大限制的问题
  • teragen/terasort_简化版
  • 云计算节点故障自动化运维服务设计
  • Redis 中的布隆过滤器
  • git操作:在CentOS7上面搭建GitLab服务器
  • windows下redis 开机自启动
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • extjs4学习之配置
  • Facebook AccountKit 接入的坑点
  • IDEA常用插件整理
  • Java的Interrupt与线程中断
  • Java读取Properties文件的六种方法
  • java中具有继承关系的类及其对象初始化顺序
  • LeetCode算法系列_0891_子序列宽度之和
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • MySQL用户中的%到底包不包括localhost?
  • PHP那些事儿
  • Sass Day-01
  • text-decoration与color属性
  • vue-cli3搭建项目
  • webpack4 一点通
  • Yeoman_Bower_Grunt
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 前端面试之CSS3新特性
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 树莓派 - 使用须知
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 一些css基础学习笔记
  • 用Visual Studio开发以太坊智能合约
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​渐进式Web应用PWA的未来
  • # 安徽锐锋科技IDMS系统简介
  • #QT(TCP网络编程-服务端)
  • (09)Hive——CTE 公共表达式
  • (二)丶RabbitMQ的六大核心
  • (剑指Offer)面试题34:丑数
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET 中让 Task 支持带超时的异步等待
  • .NET基础篇——反射的奥妙
  • .net开发时的诡异问题,button的onclick事件无效
  • :not(:first-child)和:not(:last-child)的用法
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @Pointcut 使用
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧