kvo概述

  kvo,全称Key-Value Observing,它提供了一种方法,当对象某个属性发生改变时,允许监听该属性值变化的对象可以接受到通知,然后通过kvo的方法响应一些操作。

kvo实现原理

  kvo是如何实现通知对象的呢,其实这是通过Objective-C强大的runtime运行时机制实现的。当你第一次观察某个对象时,runtime会创建一个新的继承被监听类的子类。在这个新的类中,它会重写所有被观察的key,然后将对象的isa指针指向新创建的类。所以对象神奇的变成了新的子类的实例。这些被重写的方法中添加了调用通知观察者的方法的代码。当一个对象的一个属性改变时,会触发setKey方法,但这个方法被重写了,并且在内部添加了发送通知机制。

kvo实现原理验证实验

  1.我们新建一个Single View Application工程。然后新建一个Person类和一个Dog类。

  2.在Person.h中增加一个属性age。

#import <Foundation/Foundation.h>

@interface Person : NSObject//新增一个age属性
@property (nonatomic,assign) int age;

@end

  3.在Dog.m中添加kvo监听方法observeValueForKeyPath:ofObject:change:context:

#import "Dog.h"

@implementation Dog
//kvo监听方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"%@监听到了%@对象的%@属性的值改变了:%@",self ,object ,keyPath ,change);
}

@end

  4.在ViewController.m文件中添加如下代码

#import "ViewController.h"
#import "Person.h"
#import "Dog.h"

@interface ViewController ()

@property (nonatomic, strong)Person *person;
@property (nonatomic, strong)Dog *dog;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.person = [[Person alloc] init];
    self.dog = [[Dog alloc] init];

    self.person.age = ;

    //self.dog 监听self.person的age属性
    [self.person addObserver:self.dog forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];

}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.person.age = ;
}

  从上面的代码可以看出,视图加载成功后,Dog就可以监听Person的age属性的变化了。

  5.我们运行程序,然后点击空白屏幕,就会看到如下输出,说明我们的确实已经能够使用kvo监听属性变化了。

  6.然后我们通过打断点的方式,会看到在调用addObserver:forKeyPath:options:context:方法前后Person所属类是不同的。

    添加观察器之前:

  添加观察器之后:

  通过前后对比,我们发现当person对象被监听后,系统在运行时动态创建了一个继承自Person的子类NSKVONOtifying_Person类。然后KVO会在这个派生类中,重写基类中任何被观察属性的setter方法,在setter方法中实现真正的通知机制。

- (void)setAge:(int)age

{

[super setAge:age];

[监听者 observeValueForKeyPath:@"age"  ofObject:self  change:@{}  context:nil];

}

  KVO是一个很强大的工具,有时候过于强大了,尤其是有了自动触发通知机制。现在我们知道了它的工作原理,知道使用它会在运行时创建一个新的类,所以性能会有一定影响,因此除非非要监听某个属性值的变化时候才使用它。这些知识或许能帮助你更好地使用它,或在它出错时更方便调试。

KVO的内部实现原理的更多相关文章

  1. KVO内部实现原理

    KVO的原理: 只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象, (格式如:NSKVONotifying_className), 并且重写自动生成的子类对象的被监听 ...

  2. Mininet的内部实现原理简介

    原文发表在我的博客主页,转载请注明出处. 前言 之前模拟仿真网络一直用的是Mininet,包括写了一些关于Mininet安装,和真实网络相连接,Mininet简历拓扑的博客,但是大多数都是局限于具体步 ...

  3. Angular单页应用&AngularJS内部实现原理

    回顾 自定义指令 登录后获取登录信息session 首先在登录验证的时候保存一个user 在学生管理页面中运用ajax调用获取到登录的用户信息 对注销按钮添加点击事件:调用ajax在表现层给user赋 ...

  4. 8. 理解ZooKeeper的内部工作原理

    到目前为止,我们已经讨论了ZooKeeper服务的基础知识,并详细了解了数据模型及其属性. 我们也熟悉了ZooKeeper 监视(watch)的概念,监视就是在ZooKeeper命名空间中的znode ...

  5. Redis有序集内部实现原理分析(二)

    Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read 本篇博文紧随上篇Redis有序集内部实现原理分析,在这篇博文 ...

  6. (译)KVO的内部实现

    09年的一篇文章,比较深入地阐述了KVO的内部实现.   KVO是实现Cocoa Bindings的基础,它提供了一种方法,当某个属性改变时,相应的objects会被通知到.在其他语言中,这种观察者模 ...

  7. [转](译)KVO的内部实现

    转载自:http://www.cocoachina.com/applenews/devnews/2014/0107/7667.html   09年的一篇文章,比较深入地阐述了KVO的内部实现.   K ...

  8. Apache Lucene评分机制的内部工作原理

    Apache Lucene评分机制的内部工作原理' 第5章

  9. Flask源码分析二:路由内部实现原理

    前言 Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1. 上次了解了 ...

随机推荐

  1. hook_schema 小总结

    1, primary key 可以带空格 做为下表 但field就不行 2, dev_node 仅为下标 'primary key' => array('nid'),    'foreign k ...

  2. 【转】PackageInfo、ResolveInfo 笔记

    1.PackageInfo.ResolveInfo PackageItemInfo:包含了一些信息的基类, 它的直接子类有: ApplicationInfo. ComponentInfo.Instru ...

  3. XP系统电脑带安卓手机上网教程(无需adhoc补丁)

    XP系统电脑带安卓手机上网教程(无需adhoc补丁) WIN7系统可以虚拟wifi热点,安卓手机连上这个热点就能上网.XP系统虚拟出来的wifi热点是adhoc形式的,原生的安卓系统并不支持adhoc ...

  4. iOS 国际化多语言设置 xcode7

    iOS 国际化多语言设置 方式一: 1. 在storyboard中创建好UI,然后在 project 里面  Localizables 栏目里面,添加你需要的语言:默认是Englist; 比如这里我添 ...

  5. centos7 修改selinux 开机导致 faild to load SELinux policy freezing 错误

    centos7 修改selinux 开机导致 faild to load SELinux policy  freezing 错误 之前把selinux关闭了,这次想打开selinux,于是修改了 /e ...

  6. 扩展Date的DateDiff方法--日期差

    Date.prototype.DateDiff = function(after){ var diffDay; var beforeDate = new Date(this).format(" ...

  7. jmeter生成报告指示板

    JMeter支持仪表板图表和报告生成 数据从一个测试计划. 这一章描述了如何配置和使用生成器. 概述 JMeter的仪表板生成器是一个模块化的扩展. 它的缺省行为是读取和处理样本 CSV文件生成HTM ...

  8. Shell基础:变量类型 & 运算符

    Shell变量 Shell支持三种类型的变量 用户自定义变量:用户自定义的变量,变量名以英文字母或下划线开头,区分大小写. 位置变量:根据位置传递参数给脚本的变量,默认支持9个位置变量 $1,$2,$ ...

  9. windows下修改mysql用户名和密码

    1.关闭正在运行的MySQL. 2.打开DOS窗口,转到mysql\bin目录. 3.输入mysqld-nt --skip-grant-tables回车.如果没有出现提示信息,那就对了. 4.再开一个 ...

  10. svn resolve/merge

    svn merge http://svn.a.com/branches/20150129_168954_sales-impr_1 svn resolve --accept working web/sr ...