KVC与KVO
来源:互联网 发布:node co模块 阮一峰 编辑:程序博客网 时间:2024/06/06 05:19
OC中具有很多的动态特性:例如动态类型,动态加载,动态绑定等,这里KVC(键值编码)与KVO(键值监听)也是比较常见的。
1:键值编码(KVC),用于动态属性赋值操作。
KVC的操作时由NSKeyValueCoding协议提供,NSObject对象就实现了这个协议,也就是说OC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:
(1):
/**
KVC的一般操作用于简单路径
@param value 要设置的对象value
@param key 要设置的对象的key
*/
- (void)setValue:(nullableid)value forKey:(NSString *)key;
(2):
/**
KVC的常用方法二(用于复合路径)
给某个自定义对象的某个属性赋值就是复合路径
@param value 要设置的对象value
@param keyPath 要设置的对象的的属性路径
*/
-(void)setValue:(nullableid)value forKeyPath:(NSString *)keyPath;
下面通过一个例子理解KVC
//
// info.h
// KVC
//
// Created by MiHu on 2016/12/8.
// Copyright © 2016年 MiHu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface info : NSObject
/**
属性:成绩
*/
@property(nonatomic,assign)NSInteger score;
@end
//
// info.m
// KVC
//
// Created by MiHu on 2016/12/8.
// Copyright © 2016年 MiHu. All rights reserved.
//
#import "info.h"
@implementation info
@end
// person.h
// KVC
//
// Created by MiHu on 2016/12/8.
// Copyright © 2016年 MiHu. All rights reserved.
//
#import <Foundation/Foundation.h>
@class info;
@interface person : NSObject{
@private
int _age;
}
/**
属性:姓名
*/
@property(nonatomic,strong)NSString *name;
/**
属性:info
*/
@property(nonatomic,strong)info * info;
/**
公共方法
*/
-(void)showMessage;
@end
// person.m
// KVC
//
// Created by MiHu on 2016/12/8.
// Copyright © 2016年 MiHu. All rights reserved.
//
#import "person.h"
@implementation person
-(void)showMessage
{
NSLog(@"name=%@,age=%d",_name,_age);
}
@end
// ViewController.m
// KVC
//
// Created by MiHu on 2016/12/8.
// Copyright © 2016年 MiHu. All rights reserved.
//
#import "ViewController.h"
#import "info.h"
#import "person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
person * per = [[personalloc]init];
[per setValue:@"jac"forKey:@"name"];
[per setValue:@20forKey:@"age"];//注意即使是私有变量也能访问
[per showMessage];
//输出:name=jac,age=20
info * Info = [[infoalloc]init];
per.info = Info;//注意这一步一定要先给account属性赋值,否则下面按路径赋值无法成功,因为account为nil,当然这一步骤也可以写成:[per setValue:account1 forKeyPath:@"account"];
[per setValue:@100forKeyPath:@"info.score"];
NSLog(@"per's balance is :%.2f",[[pervalueForKeyPath:@"info.score"]floatValue]);
//输出:per's balance is :100.00
}
@end
KVC使用起来比较简单,但是它如何查找一个属性进行读取呢?具体查找规则(假设现在要利用KVC对a进行读取):
如果是动态设置属性,则优先考虑调用setA方法,如果没有该方法则优先考虑搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的setValue:forUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确设置);
如果是动态读取属性,则优先考虑调用a方法(属性a的getter方法),如果没有搜索到则会优先搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的valueforUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确读取)
2: 键值监听KVO
KVO其实是一种观察者模式,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器 的视图组件就会被激发,激发时就会回调监听器自身。在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是 NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO
在OC中使用KVO的一般方法为:
/**
注册指向指定key路径的监听器
@param observer 谁来监听
@param keyPath key路径
@param options NSKeyValueObservingOptions
@param context 上下文
*/
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid *)context;
/**
移除指定Key路径的监听器
@param observer 谁来监听
@param keyPath key路径
@param context 上下文
*/
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7,5_0);
/**
回调监听:
@param keyPath key路径
@param object 谁发起的
@param change NSKeyValueChangeKey
@param context 上下文
*/
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
KVO的使用方法也很简单:
- 通过addObserver: forKeyPath: options: context:为被监听对象(它通常是数据模型)注册监听器
- 重写监听器的observeValueForKeyPath: ofObject: change: context:方法
继续上面的例子介绍KVO 我们希望当对象的姓名发生改变的时会回调监听方法。那么此时姓名就作为我们的被监听对象,需要Person为它注册监听(使用addObserver: forKeyPath: options: context:);而人员Person作为监听器需要重写它的observeValueForKeyPath: ofObject: change: context:方法,当监听的成绩发生改变后会回调监听器Person监听方法(observeValueForKeyPath: ofObject: change: context:)
#import "ViewController.h"
#import "info.h"
#import "person.h"
@interface ViewController()
@property(nonatomic,strong)person * per;
@end
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
_per = [[personalloc]init];
info *Info = [[infoalloc]init];
_per.info = Info;
[_persetValue:@"jac"forKey:@"name"];
[_persetValue:@90forKeyPath:@"info.score"];
[_peraddObserver:selfforKeyPath:@"name"options:(NSKeyValueObservingOptionNew)context:nil];
_per.name =@"jenny";
}
#pragma mark - 覆盖方法
#pragma mark 重写observeValueForKeyPath方法,当姓名变化后此处获得通知
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
//只处理姓名改变
if([keyPathisEqualToString:@"name"])
{
NSLog(@"我改名字了");
}
}
#pragma mark 重写销毁方法
-(void)dealloc
{
[selfremoveObserver:selfforKeyPath:@"name"];
}
- 理解KVC与KVO
- KVC 与 KVO 理解
- KVC 与 KVO 理解
- KVC 与 KVO 理解
- KVC与KVO
- KVC 与 KVO 理解
- KVC与KVO解析
- kvc与kvo
- KVC与KVO:
- KVC 与 KVO 理解
- KVC 与 KVO 理解
- 【iOS】KVC 与 KVO
- KVC 与 KVO 理解
- KVC与KVO理解
- KVC 与 KVO 理解
- KVC 与 KVO 理解
- KVC 与 KVO 理解
- KVC与KVO
- [做题笔记] 2016/12/1
- 蓝桥杯: Cowboys
- 将一个数插入到有序的数列中,插入后的数列仍然有序
- 项目管理---git----快速使用git笔记(一)------git的简单介绍
- 零件分组
- KVC与KVO
- JS中一些数组的操作方式实例
- nodeJs学习
- iframe怎么自适应付父窗口的高度
- java 递归取树结构数据
- scrapy安装中出现的问题
- Peridynamic - Paraview 可视化1 -- 前处理步骤
- 数据结构与算法的选择
- 自定义控件属性