KVC讲解
今天趁着项目bug修复完了,来讲解一下OC知识的另一个技术点-KVC!针对KVC,讲解两个知识点
- 通过KVC修改属性会触发KVO么?
- KVC的赋值过程是怎样的?原理是什么?
- KVC的取值过程是怎样的?原理是什么?
一、问:通过KVC修改属性会触发KVO么?
答:会触发KVO
创建工程项目TestKVO,ZXYPerson类有一个属性age,在控制器ViewController中添加属性观察者KVO,项目代码如下
@interface ViewController ()
@property(nonatomic,strong) ZXYPerson *p;
@end @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad]; _p = [[ZXYPerson alloc]init];
_p.age = ; [_p addObserver:self forKeyPath:@"age" options: NSKeyValueObservingOptionNew context:nil];
[_p setValue:@12 forKeyPath: @"age"]; } -(void)dealloc {
[_p removeObserver:self forKeyPath:@"age"];
} - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"*********%@", change);
}
上面橙色文字通过KVC方式更改属性的值,将上面代码运行结果如下:

通过上面发现setValue:forKeyPath触发了KVO,同理发现setValue:forKey也会触发KVO,但是这两个方法有什么区别呢?
setValue:forKeyPath会一层一层的(沿着路径)向下找,然而setValue:forKey并不会这样!(假如ZXYPerson养了一只猫,猫有age属性 ,通过"_p.cat.age"设置应该用setValue:forKeyPath,不能用setValue:forKey)
思考: 为什么KVC更改属性值会触发KVO?那就需要讲解下面知识。
二、问:KVC的赋值过程是怎样的?原理是什么?
setValue:forKey:的原理

accessInstanceVariablesDirectly方法的默认返回值是YES
下面一一验证上面的顺序:
验证setValue:forkey调用过程不需要用到KVO,去除多余的代码之后,简化成如下:
#import "ViewController.h"
#import "ZXYPerson.h" @interface ViewController () @property(nonatomic,strong) ZXYPerson *p;
@end @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad]; _p = [[ZXYPerson alloc]init];
[_p setValue:@ forKeyPath: @"age"]; } @end #import "ZXYPerson.h" @implementation ZXYPerson - (void) setAge:(int)age {
NSLog(@"调用了setAge方法");
} - (void) _setAge: (int)age {
NSLog(@"调用了_setAge方法");
} @end
去除了age属性的声明,看看KVC赋值的前期过程(按照setKey, _setKey方法走)

同时写了两个方法,优先调用setAge方法,假如将setAge方法注释掉

注释掉setAge方法后,久调用了_setAge方法,证实了KVC的前期赋值情况!
如果两个方法都没有实现,此时KVC会看accessInstanceVariablesDirectly方法,返回Yes代表可以直接访问成员变量,反之不能访问成员变量!
如果返回为Yes,会按照_key、_isKey、key、isKey成员属性进行赋值
此时像上面的代码加入这四个成员变量,如下(前提accessInstanceVariablesDirectly方法返回Yes)
@interface ZXYPerson : NSObject
{
@public
int _age;
int _isAge;
int age;
int isAge;
} @end
加入上述代码,运行

首先给_age赋值,当四个成员变量同时出现,假如将int _age成员变量注释掉,如下:

发现当_age注释掉之后,优先给_isAge赋值,优先级仅次于_age,假如将_isAge注释掉之后

发现给age赋值,同理将age成员变量注释掉之后

最后给isAge赋值,符合了上述setValue:forkey的访问属性的优先级 _key > _isKey > key > isKey的顺序
如果这四个成员变量都没有了,就会报异常

通过上面讲述知道setValue:forKey会触发KVO
[_p setValue:@12 forKeyPath: @"age"]内部调用相当于
[p willChangeValueForKey @"age"]
p->_age = 12;
[p didChangeValueForKey @"age"]
所以会触发KVO
以上就是setValue:forKey的赋值所有过程,希望大家再看看上述图,下面讲述KVC如何取值?
三、问: KVC的取值过程是怎样的?原理是什么?
valueForKey:的原理

下面一一验证上面的顺序:
@interface ZXYPerson : NSObject{
@public
int _age;
}
@implementation ZXYPerson
- (int)getAge {
return ;
}
- (int)age {
return ;
}
- (int)isAge {
return ;
}
- (int)_age {
return ;
}
@end
@interface ViewController ()
@property(nonatomic,strong) ZXYPerson *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_p = [[ZXYPerson alloc]init];
_p->_age = ;
NSLog(@"******%@",[_p valueForKey:@"age"]);
}
@end
看看KVC取值的前期过程(按照getAge > age > isAge > _age 方法走)

当有四个方法时,会优先调用getAge方法,如上面一样打印出11,调用了getAge方法!假如把getAge()方法注释掉,运行代码:

将getAge()方法注释掉后,调用了age方法,验证了getAge > age !假如把age方法注释掉

将getAge()和age()方法注释掉后,调用了isAge()方法,验证了getAge > age > isAge !假如把isAge()方法注释掉

将getAge()和age()方法以及isAge()注释掉后,调用了_age()方法,验证了getAge > age > isAge > _age!
如果四个方法都没有实现,此时KVC会看accessInstanceVariablesDirectly方法,返回Yes代表可以直接查找成员变量,反之不能查找成员变量!
如果返回为Yes,会按照_key、_isKey、key、isKey成员属性顺序查找成员变量
此时像上面的代码加入这四个成员变量,如下(前提accessInstanceVariablesDirectly方法返回Yes,去除四个方法)
@public
int _age;
int _isAge;
int age;
int isAge;
加入了四个成员变量,控制器ViewController加入设置属性的四个值的
_p->_age = ;
_p->_isAge = ;
_p->age = ;
_p->isAge = ;
观察成员变量的查找顺序!验证_key、_isKey、key、isKey

ZXYPerson有四个成员变量,当向着上面代码书写,运行代码结论是11,对应着_age这个成员变量,所以优先取值_age!当将 _age成员变量注释掉以及赋值注释掉后

发现运行结果为12,对应的结果时_isAge, 得出结论 _age > _isAge! 继续将_isAge成员变量注释掉以及赋值_isAge如下:

发现运行结果为13,对应的结果时age, 得出结论 _age > _isAge > age! 继续将age成员变量注释掉以及赋值age如下:

发现运行结果为14,对应的结果时isAge, 得出结论 _age > _isAge > age > isAge! 继续将isAge成员变量注释掉以及赋值isAge如下:

如果都注释掉,会报异常valueForUndefinedKey错误!
以上就是valueForKey的取值所有过程,希望大家再看看上述图回顾KVC如何取值!
上述就是KVC的基本内容,希望对大家有所帮助,可以关注博客会实时更新,谢谢!!!
KVC讲解的更多相关文章
- Objective-C KVC讲解,包你看懂会用
KVC:Key Value Coding,取其三个单词首字母浓缩而成.直白翻译过来就是键值编码,什么意思呢?简单来说,就是操作一个对象,也可以像操作字典一样,通过key来取值和赋值. 我们先创建一个H ...
- FMDB源码解析
上一篇博客讲述SQLite的使用,本篇将讲述FMDB源码,后面也会讲解SQLite在使用与FMDB的区别.本篇读下来大约20-30分钟,建议大家先收藏一下. FMDB是以OC方式封装SQLite中C语 ...
- iOS KVC详细讲解
iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...
- KVC 与 KVO 理解
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
- KVC浅析和实例
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
- OC:属性、点语法、KVC
//属性的属性 属性定义在一个 .h文件里,在这个.h文件里可以定义实例变量(就是这个类的特征),也可以通过 @protery(属性约束关键字) 属性名字类型 属性名 来定义一些属性,在prope ...
- iOS开发技巧系列---详解KVC(我告诉你KVC的一切)
KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...
- 告诉你KVC的一切-b
KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...
- KVC 与 KVO 理解-b
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
随机推荐
- jenkins-构建job成功后自动打tag到git仓库
需求:最近开发同事提出了个要求,每当Jenkins执行上线部署完成后,对当前代码进行自动打TAG到git仓库中,且只有当部署成功后才进行打TAG,防止构建失败也进行打过多的垃圾tag,然后便于下次进行 ...
- iOS围绕某点缩放或旋转的AnchorPoint的设定
经常会遇到需求,要求手势的缩放或者旋转操作,要求动作变化围绕某一个特定点,或者是两指的中心点,或者是某一个点. 这个问题首先要清晰的知道,iOS各个view的层次关系.特别是,要清除的知道,当前vie ...
- 基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境
基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境 前言一.环境准备环境介绍软件下载VMware下安装UbuntuUbuntu下Anaconda的安 ...
- 什么是SSH与SSH客户端
1.什么是SSH? SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议.SS ...
- Redux 架构理解
Redux 是一种前端“架构模式”,是 Flux 架构的一种变种,用来提供可预测的状态管理.虽然经常和 React 一起被提及,但是 Redux 却不仅仅只能用于 React,还可以将其运用到其他前端 ...
- Oracle 11g rac中关于crsctl stop cluster/crs/has的区别
转载至http://www.oracleplus.net/arch/1203.html,整理后得. 1 通过命令查看cluster/has/crs管理的内容 [root@11rac1 ~]# crsc ...
- Redis主从原理及哨兵模式
1.Redis主从搭建 主从的搭建很简单,主节点设置连接密码,从节点的配置上主节点的ip和端口,以及密码,一般从节点我们都设置只读模式. 主节点配置: 主节点密码: requirepass xxx 从 ...
- Java Grammar(二):运算符
运算符简介 计算机自打诞生以来,用作最多的就是进行计算,而计算离不开运算符,所以运算符在我们的Java语言中的地位举足轻重,我们现在就来了解一下Java给我们提供的运算符. 从运算的元素的个数来区分, ...
- 【Python】2.14&2.15学习笔记 运算符与表达式
太爽了,今天可以尽情熬夜了,明天不上课,可以学一整天\(Python\) 运算符 \(+,-,*,%\)就不说了,说几个和\(c\)不太一样的 除法 print( 5/3 ) 输出了\(1.66666 ...
- Javaweb编程
首先是题目要求: 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求显示“• ”或“*”表示输入位数,密码要求八位以上字母.数字组成.(1分) 3性别:要 ...