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)并不是什么新鲜事物,它来源于设计模式中的观察者模式,其基本思想就是: 一个目标对象管理所有依赖于它的观察者对象,并在它 ...
随机推荐
- Java 向Hbase表插入数据报(org.apache.hadoop.hbase.client.HTablePool$PooledHTable cannot be cast to org.apac)
org.apache.hadoop.hbase.client.HTablePool$PooledHTable cannot be cast to org.apac 代码: //1.create HTa ...
- oracle drop table and purge
一.drop表 执行drop table xx 语句 drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 通过查询回收站 ...
- NIO学习:异步IO实例
工作模式: 客户端代码: package demos.nio.socketChannel; import java.io.ByteArrayOutputStream; import java.io.I ...
- Android_EditText
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...
- Bootstrap与tab组合,切换菜单实例
<html><head><meta http-equiv="Content-Type" content="text/html; charse ...
- 【排障】使用DiskGenius修复0扇区损坏
用PE引导启动进入PE后打开DiskGenius软件 "硬盘"图形菜单------选择驱动器符号(例如C) 主界面中显示该硬盘的分区格式为FAT32,起始柱面0,起始磁头65. 在 ...
- easyui-textbox
TextBox 扩展自 $.fn.validatebox.defaults. 重写 $.fn.textbox.defaults. TextBox 是加强的输入控件,使我们建设表单更加快捷. 是一些复杂 ...
- webbreswer
为了帮助网友解决"怎么用C#的webBrowser模拟点击页面上的标签"相关的问题,中国学网通过互联网对"怎么用C#的webBrowser模拟点击页面上的标签" ...
- Lucene.net常用功能说明
Lucene.net是一个.net下的全文检索类库.配置简单,功能丰富,比较成熟.我在项目中用Lucene.net有一段时间了,这里我把常用一些功能写出来,与大家一起分享. Lucene.net用的是 ...
- 添加samba用户,并设置密码
5.3.3 添加samba用户,并设置密码; 我们用的方法是先添加用户,但添加的这些用户都是虚拟用户,因为这些用户是不能通过SHELL登录系统的;另外值得注意的是系统用户密码和Samba用户的密码是不 ...