【原】iOS中KVC和KVO的区别
在iOS开发中经常会看到KVC和KVO这两个概念,比较可能混淆,特地区分一下
KVC(Key Value Coding)
1> 概述
KVC:Key Value Coding,键值编码,是一种间接访问实例变量的方法。
KVC 提供了一个使用字符串(Key)而不是访问器方法,去访问一个对象实例变量的机制。
2> KVC部分源码(头文件)
// NSKeyValueCoding.h
@interface NSObject(NSKeyValueCoding) + (BOOL)accessInstanceVariablesDirectly; - (nullable id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; - (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0); - (NSMutableSet *)mutableSetValueForKey:(NSString *)key; - (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath; - (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
- (void)setNilValueForKey:(NSString *)key;
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues; @end @interface NSArray<ObjectType>(NSKeyValueCoding) - (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key; @end @interface NSDictionary<KeyType, ObjectType>(NSKeyValueCoding) - (nullable ObjectType)valueForKey:(NSString *)key; @end @interface NSMutableDictionary<KeyType, ObjectType>(NSKeyValueCoding) - (void)setValue:(nullable ObjectType)value forKey:(NSString *)key; @end @interface NSOrderedSet<ObjectType>(NSKeyValueCoding) - (id)valueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
- (void)setValue:(nullable id)value forKey:(NSString *)key NS_AVAILABLE(10_7, 5_0); @end @interface NSSet<ObjectType>(NSKeyValueCoding) - (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key; @end
可以看到这个类里面包含了对类NSObject、NSArray、NSDictionary、NSMutableDictionary、NSOrderedSet、NSSet的扩展,扩展方法基本上为
- (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
也就是说,基本上Objective-C里所有的对象都支持KVC操作,操作包含如上两类方法,动态读取和动态设值。
3> 通过KVC键值编码访问属性
① key值查找
[stu setValue:@"xiaoqiang" forKey:@"name"];
[stu setValue:@"boy" forKey:@"gender"];
[stu setValue:@ forKey:@"age"]; NSLog(@"name = %@, gender = %@, age = %@", [stu valueForKey:@"name"], [stu valueForKey:@"gender"], [stu valueForKey:@"age"]);
② 路径查找
Teacher *tea = [[Teacher alloc] init];
stu.teacher = tea;
[stu setValue:@"fangfang" forKeyPath:@"teacher.name"]; // 路径查找
NSLog(@"teacherName = %@", [stu valueForKeyPath:@"teacher.name"]);
③ 同时给多个属性赋值
NSDictionary *dict = @{
@"name" : @"fangfang",
@"gender" : @"girl",
@"age" : @,
@"hobby" : @"fangfang"
};
Student *stu2 = [[Student alloc] init];
// 同时给多个属性赋值
[stu2 setValuesForKeysWithDictionary:dict];
NSLog(@"name = %@, gender = %@, age = %ld", stu2.name, stu2.gender, stu2.age);
4> KVC抛出异常的方法
① 使用KVC设置值对象时
如果当前类没有找到对象的Key值,系统会自动调用 setValue: forUndefinedKey: 方法
该方法的默认实现是抛出一个异常,如果不想抛出异常,就重写这个方法
// 重写
// 使用KVC设置值对象
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
NSLog(@"不存在Key:%@", key);
}
② 使用KVC取值的时候
如果当前类没有找到对应的Key值,系统会自动调用 valueForUndefinedKey: 方法
该方法的默认实现是抛出一个异常,如果不想抛出异常,就重写这个方法
// 重写
// 使用KVC取值的时候
- (id)valueForUndefinedKey:(NSString *)key
{
return nil;
}
5> KVC的实现机制
KVC按顺序使用如下技术:
- 检查是否存在getter方法-<key>或者setter方法-set<key>:的方法;
- 如果没有上述方法,则检查是否存在名字为-_<key>、<key>的实例变量;
- 如果仍未找到,则调用 valueForUndefinedKey: 和 setValue: forUndefinedKey: 方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
KVO(Key Value Observer)
1> 概述
KVO:(Key Value Observer)键值观察者,是观察者设计模式的一种具体实现
KVO触发机制:一个对象(观察者),监测另一对象(被观察者)的某属性是否发生变化,若被监测的属性发生的更改,会触发观察者的一个方法(方法名固定,类似代理方法)
2> 一部分NSKeyValueObserving.h对于NSObject的拓展代码
@interface NSObject(NSKeyValueObserving) - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context; @end @interface NSObject(NSKeyValueObserverRegistration) - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath; @end
从拓展名称就可以看出,使用KVO需要注册监听器,也需要删除监听器。监听过程需要使用observeValueForKeyPath回调方法。
3> 使用步骤
注册观察者(为被观察者指定观察者以及被观察属性)
// KVO 键值观察,是观察者设计模式
@interface ViewController () // 观察可变数组的改变情况(苹果官方文档不建议对数组进行观察)
@property (nonatomic, strong) NSMutableArray *array; @end - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. self.array = [NSMutableArray array]; // 第一步:注册观察者
// 参数1:添加的观察者对象
// 参数2:字符串标识的key
// 参数3:触发添加观察者对象的时候
/*
NSKeyValueObservingOptionNew = 0x01 key或value只要有一个更新的时候就会触发
NSKeyValueObservingOptionOld = 0x02
NSKeyValueObservingOptionInitial = 0x04
NSKeyValueObservingOptionPrior = 0x08
*/
// 参数4:文本内容 一般为nil
[self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew context:nil];
}
实现回调方法
// 第二步:实现回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{ NSLog(@"keyPath = %@", keyPath);
NSLog(@"object = %@", object);
NSLog(@"change = %@", change); // 可以进行刷新UI的操作
}
触发回调方法(被观察属性发生更改)
// 第二步:实现回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{ NSLog(@"keyPath = %@", keyPath);
NSLog(@"object = %@", object);
NSLog(@"change = %@", change); // 可以进行刷新UI的操作
}
移除观察者
在不需要观察者的时候需要把它删除,本人就只在视图将要消失时移除
// 视图将要消失的时候
- (void)viewWillDisappear:(BOOL)animated
{
// 在不需要观察者的时候需要把它删除
[self removeObserver:self forKeyPath:@"array"];
}
【原】iOS中KVC和KVO的区别的更多相关文章
- iOS 中KVC、KVO、NSNotification、delegate 总结及区别-b
1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性.而不是通过调用Setter.Getter方法访问.KVO 就是基于 KVC 实现的 ...
- iOS开发中KVC、KVO简介
在iOS开发中,KVC和KVO是经常被用到的.可以使用KVC对对象的属性赋值和取得对象的属性值,可以使用KVO监听对象属性值的变化.简单介绍一下KVC和KVO. 一:键值编码(KVC) KVC,全称 ...
- [转] iOS (OC) 中 KVC 与 KVO 理解
转自: http://magicalboy.com/kvc_and_kvo/ KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value ...
- iOS开发-KVC和KVO的理解
KVC和KVO看起来很专业,其实用起来还是比较简单的,KVC(Key-value coding)可以理解为键值对编码,如果对象的基本类型,那么键值对编码实际上和get,set方法没有区别,如果是属性是 ...
- IOS之KVC和KVO(未完待续)
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- 【iOS】KVC 与 KVO
一.KVC与KVO *"KVC":key value Coding(键值编码) *目的:间接的改动或获取对象的属性,减少程序(类与类)之间的耦合度. *"KVO" ...
- KVC和KVO的区别
kvc和kvo 1.kvc Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性.KVO 就 ...
- IOS 中frame与bounds的区别
文章摘要:http://www.sendong.com/news1733.html bounds是指这个view在它自己坐标系的坐标和大小 而frame指的是这个view在它superview的坐标系 ...
- iOS中的#import和class区别
在ios中我们经常会在.h和.m中引入一些类啊等等一般用的是#import来进行声明,你们可能也见到在.h文件进用@class来声明的,那么#import和@class进行声明 到底有什么的区别呢?下 ...
随机推荐
- JavaScript数组排序
JavaScript的sort方法排序是有问题的,我们可以给sort方法传一个参数 function Compare(value1, value2) { //数字排序的函数参数 if (value1 ...
- 查询Oracle中字段名带"."的数据
SDE中的TT_L线层会有SHAPE.LEN这样的字段,使用: SQL>select shape.len from tt_l; 或 SQL>select t.shape.len from ...
- Swift - 文件目录路径获取及数据储存(Home目录,文档目录,缓存目录)
iOS应用程序只能在自己的目录下进行文件的操作,不可以访问其他的存储空间,此区域被称为沙盒. 应用沙盒结构分析 1.应用程序包:包含了所有的资源文件和可执行文件 2.Documents:保存应用运 ...
- Android界面性能调优手册
界面是 Android 应用中直接影响用户体验最关键的部分.如果代码实现得不好,界面容易发生卡顿且导致应用占用大量内存. 我司这类做 ROM 的公司更不一样,预装的应用一定要非常流畅,这样给客户或用户 ...
- bootstratp图标的使用
bootstratp作为一个优秀的前端框架,最近使用了其中的Glyphicon Halflings的字体图标.起初一直显示不出来,后面通过搜索相关资料直到成功显示,在此做一些总结,方便后面复习. 1. ...
- 排队打饭 sdut 2443【最简单的贪心法应用举例】
排队打饭 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 题目链接:http://acm.sdut.edu.cn/sdutoj/p ...
- 在python多进程中使用manager和Barrier
注意:Barrier是PYTHON3才有的功能,在2中无法测试. #!/usr/bin/env python # -*- coding: utf-8 -*- import multiprocessin ...
- C# Func<T,TResult>
using System; namespace FuncDemo { internal class Program { private static void Main() { //类似委托功能 Fu ...
- hdu 4034 2011成都赛区网络赛 逆向floyd **
给出一个最短路邻接矩阵,求出构图的最小边数 正常的floyd的k放在最外面是为了防止i到j的距离被提前确定,而逆向的floyd,i到j的距离已经确定,所以需要在i到j之间枚举k,注意需要break,否 ...
- EF Core 1.0中使用Include的小技巧
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:由于EF Core暂时不支持Lazy Loading,所以利用Include来加载额外 ...