KVO - 键值观察
【基本概念】
键值观察是一种使对象获取其他对象的特定属性变化的通知机制。控制器层的绑定技术就是严重依赖键值观察获得模型层和控制器层的变化通知的。对于不依赖控制器层类的应用程序,键值观察提供了一种简化的方法来实现检查器并更新用户界面值。
与NSNotification不同,键值观察并没有所谓的中心对象来为所有观察者提供变化通知。取而代之的,当有变化发生时,通知被直接发送至处于观察状态的对象。NSObject提供这种基础的键值观察实现方法,你几乎不用重写该方法。
你可以观察任意对象属性,包括简单属性,对一或是对多关系。对多关系的观察者将会被告知发生变化的类型-也就是任意发生变化的对象。键值观察为所有对象提供自动观察兼容性。你可以通过禁用自动观察通知并实现手动通知来筛选通知。
【注册观察者】
为了正确接收属性的变更通知,观察者必须首先发送一个addObserver:forKeyPath:options:context:消息至被观察对象,用以传送观察对象和需要观察的属性的关键路径,以便与其注册。选项参数指定了发送变更通知时提供给观察者的信息。使用NSKeyValueObservingOptionOld选项可以将初始对象值以变更字典中的一个项的形式提供给观察者。指定NSKeyValueObservingOptionNew选项可以将新的值以一个项的形式添加至变更字典。你可以使用逐位“|”这两个常量来指定接受上述两种类型的值。
下面我通过几个实例来带大家实现一下KVO的通知机制:
【实例一】对基本数据类型的属性进行观察
(1)我建立的是一个基于OC的iOS项目,在storyboard中拖入一个按钮,并在ViewController中使用IBAction实现按钮点击。
(2)声明一个int类型的属性在ViewController.m文件中:
- @interface ViewController ()
- @property(assign,nonatomic) int count;
- @end
(3)然后实现一个初始化方法,初始化count的值:
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- self.count = 1;
- }
- return self;
- }
(4)在按钮点击响应中进行自加运算,以后我就监听点击按钮count数值改变的这个事件:
- - (IBAction)clicked:(id)sender {
- self.count++;
- }
(5)在viewDidLoad方法中注册观察事件:
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
- }
(6)最后重写一个方法observeValueForKeyPath;如下:
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(voidvoid *)context{
- if ([keyPath isEqual: @"count"]) {
- NSLog(@"count = %d",self.count);
- }
- }
(7)输出结果如下:每当我点击按钮,观察事件就会调用注册的方法。
。
【实例二】对 对象进行观察
(1)在上述的基础上,新建一个Other类,在h头文件中声明一个变量:
- #import <Foundation/Foundation.h>
- @interface Other : NSObject
- @property(assign,nonatomic) int number;
- @end
(2)在Other.m文件中实现初始化方法,初始化number变量:
- #import "Other.h"
- @implementation Other
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- self.number = 100;
- }
- return self;
- }
- @end
(3)在ViewController.m中实现如下:
- #import "ViewController.h"
- #import "Other.h"
- @interface ViewController ()
- @property(strong,nonatomic) Other *other;
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- //监听Other类;
- self.other = [[Other alloc] init];
- [self.other addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
- }
- - (IBAction)clicked:(id)sender {
- _other.number++;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(voidvoid *)context{
- //我假设能被2整除时输出,注意我使用的是keyPath进行匹配;
- if ([keyPath isEqual: @"number"] && _other.number % 2 == 0){
- NSLog(@"other.number = %d",_other.number);
- }
- }
- @end
(4)输出结果如下:
。
【实例三】同时对多个对象进行观察
在上述【实例一】【实例二】的基础上,我同时对两个变量进行观察,其他类中的实现不变,ViewController.m中的实现如下:
- #import "ViewController.h"
- #import "Other.h"
- @interface ViewController ()
- @property(assign,nonatomic) int count;
- @property(strong,nonatomic) Other *other;
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
- //监听Other类;
- self.other = [[Other alloc] init];
- [self.other addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
- }
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- self.count = 1;
- }
- return self;
- }
- - (IBAction)clicked:(id)sender {
- _other.number++;
- self.count++;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(voidvoid *)context{
- if (object == self.other) {
- NSLog(@"number = %d",_other.number);
- }
- else if (object == self && self.count % 2 == 0){
- NSLog(@"count = %d",self.count);
- }
- }
- @end
输出结果如下:
。
【实例四】使用change参数实时观察参数变化
ViewController.m中的实现如下:
- #import "ViewController.h"
- #import "Other.h"
- @interface ViewController ()
- @property(assign,nonatomic) int count;
- @property(strong,nonatomic) Other *other;
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
- }
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- self.count = 1;
- }
- return self;
- }
- - (IBAction)clicked:(id)sender {
- _other.number++;
- self.count++;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(voidvoid *)context{
- //在这里对观察变量进行打印;
- NSLog(@"%@",change);
- }
- @end
输出结果如下:
KVO - 键值观察的更多相关文章
- K-V-O 键值观察机制
在两个不同的控制器之间传值是iOS开发中常有的情况,应对这种情况呢,有多种的应对办法.kvc就是其中的一种,所以,我们就在此解释之. key value observing 键值观察,给人一种高 ...
- iOS - KVO 键值观察
1.KVO KVO 是 Key-Value Observing 的简写,是键值观察的意思,属于 runtime 方法.Key Value Observing 顾名思义就是一种 observer 模式用 ...
- KVO(键-值观察)
// 1.键-值观察 // 2.它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知. // 3.符合KVC(Key-ValuedCoding)机制的对象才可以使用KVO // 4.实现过 ...
- KVO键值观察的具体实现
1.KVO简介 KVO是Objective-C对观察者设计模式的一种实现,它提供一种机制,指定一个被观察对象(如A类),当对象中的某个属性发生变化的时候,对象就会接收到通知,并作出相应的处理.在MVC ...
- OC键值观察KVO
什么是KVO? 什么是KVO?KVO是Key-Value Observing的简称,翻译成中文就是键值观察.这是iOS支持的一种机制,用来做什么呢?我们在开发应用时经常需要进行通信,比如一个model ...
- 路径(keyPath)、键值编码(KVC)和键值观察(KVO)
键路径 在一个给定的实体中,同一个属性的所有值具有相同的数据类型. 键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制. - 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接 ...
- 09 (OC)* 键路径(keyPath)、键值编码(KVC)、键值观察(KVO)
键路径在一个给定的实体中,同一个属性的所有值具有相同的数据类型.键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制. - 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一 ...
- 深度理解Key-Value Observing 键值观察
前言 在上一阶段的开发过程中,我们大量使用了 KVO 机制,来确保页面信息的及时同步.也因此碰到了很多问题,促使我们去进一步学习 KVO 的相关机制,再到寻找更好的解决方案.鉴于 KVO 让人欲仙 ...
- [深入浅出Cocoa]详解键值观察(KVO)及其实现机理
一,前言 Objective-C 中的键(key)-值(value)观察(KVO)并不是什么新鲜事物,它来源于设计模式中的观察者模式,其基本思想就是: 一个目标对象管理所有依赖于它的观察者对象,并在它 ...
随机推荐
- pixel实践
安装pixel .安装node.js wget http://nodejs.org/dist/v0.6.1/node-v0.6.1.tar.gz 本地测试下载的是这个版本,如果要高版本的话可以找高版本 ...
- php中error_report函数的含义及各参数含义
个错误级别,如下: 1 E_ERROR 致命的运行时错误.错误无法恢复过来.脚本的执行被暂停2 E_WARNING 非致命的运行时错误.脚本 ...
- 得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
今天进行slf4j中logger的同步封装.主要目的是为了以后方便更换日志实现系统. 遇到的问题:使用Thread.currentThread().getStackTrace()[1].getClas ...
- The 10 Most Important Security Controls Missing in JavaEE--reference
JavaEE has some excellent built-in security mechanisms, but they don’t come close to covering all th ...
- 判断app是否在后台
1.通过RunningTaskInfo类判断(需要额外权限):(测试通过5.1可用,权限名称修改 <uses-permission android:name="android.perm ...
- eclipse 注释模板设置
方法注释模板 /** * @title ${enclosing_method} * @description ${todo} * ${tags} ${return_type} * @Date ${da ...
- C#后台验证身份证号码的一个方法
简单的调用了正则表达式进行简单的验证,记下来留着以后备用 if ((!Regex.IsMatch(txtID.Text, @"^(^\d{15}$|^\d{18}$|^\d{17}(\d|X ...
- 分享4个网址二维码API接口
说明:把url=后面的网址改成你的,四种任选一.http://pan.baidu.com/share/qrcode?w=150&h=150&url=http://lanyes.org ...
- SQL Server 2008 TOP 新用途
/***************创建测试表******************************/ IF NOT OBJECT_ID('[Demo_Top]') IS NULL DROP TAB ...
- 20151212Jquery 工具函数代码备份
$(function () { /*var str=' jquery '; alert(str); alert($.trim(str));*/ /*var arr=['张三','李四','王五','麻 ...