今天趁着项目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讲解的更多相关文章

  1. Objective-C KVC讲解,包你看懂会用

    KVC:Key Value Coding,取其三个单词首字母浓缩而成.直白翻译过来就是键值编码,什么意思呢?简单来说,就是操作一个对象,也可以像操作字典一样,通过key来取值和赋值. 我们先创建一个H ...

  2. FMDB源码解析

    上一篇博客讲述SQLite的使用,本篇将讲述FMDB源码,后面也会讲解SQLite在使用与FMDB的区别.本篇读下来大约20-30分钟,建议大家先收藏一下. FMDB是以OC方式封装SQLite中C语 ...

  3. iOS KVC详细讲解

    iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...

  4. KVC 与 KVO 理解

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

  5. KVC浅析和实例

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

  6. OC:属性、点语法、KVC

    //属性的属性 属性定义在一个 .h文件里,在这个.h文件里可以定义实例变量(就是这个类的特征),也可以通过   @protery(属性约束关键字) 属性名字类型 属性名 来定义一些属性,在prope ...

  7. iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

    KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...

  8. 告诉你KVC的一切-b

    KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...

  9. KVC 与 KVO 理解-b

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

随机推荐

  1. 关于使用Binlog和canal来对MySQL的数据写入进行监控

    先说下Binlog和canal是什么吧. 1.Binlog是mysql数据库的操作日志,当有发生增删改查操作时,就会在data目录下生成一个log文件,形如mysql-bin.000001,mysql ...

  2. fork他人仓库文件及修改整合

    1.首先使用浏览器打开自己的GitHub地址,并打开即将fork的文件地址(别人的文件地址),在其右上方找到fork选项并点击即可 2.在自己的电脑上创建一个文件夹后使用git bush here的C ...

  3. iNeuOS工业互联平台,开放设备驱动管理、服务驱动管理、云组态自定义画布等,促进平台开放、赋能和落地。发布:v2.3版本。

    目       录 1.      概述... 2 2.      iNeuOS平台演示... 2 3.      设备驱动管理... 2 4.      服务驱动管理... 3 5.      云组 ...

  4. HTML实体符号代码

    1. 特色的 © © © 版权标志 |   | 竖线,常用作菜单或导航中的分隔符 · · · 圆点,有时被用来作为菜单分隔符 ↑ ↑ ↑ 上箭头,常用作网页“返回页面顶部”标识 € € € 欧元标识 ...

  5. 题解 UVA12186 【工人的请愿书 Another Crisis】

    俺太难了 记录一下我调了一个小时的错误 多测不清空 多测清空只清空了\(vector\) 多测全清空了,但是忘了清空\(vector[0]\) \(priority\)_ \(queue\)把\(gr ...

  6. hive学习_01

    1.构建在Hadoop之上的数据仓库(数据计算使用MR,数据存储使用HDFS) 2.Hive定义了一种类SQL查询语言----HQL 3.通常用于进行离线数据处理(非实时) 4.一个ETL工具 5.可 ...

  7. 由国产性能测试工具WEB压力测试仿真能力对比让我想到的

    软件的行业在中国已得到长足的发展,软件的性能测试在软件研发过程显得越来越重要.国产的性能工具在好多大公司都在提供云服务的有偿收费测试.如:阿里的PTS(Performance Testing Serv ...

  8. Linux 应用领域

    与Windows操作系统软件一样,Linux也是一个操作系统软件.但与Windows不同的是,Linux是一套开放源代码程序的,并可以自由传播的类UNIX操作系统软件,随着信息技术的更新变化,Linu ...

  9. docker安装mysql主从

    docker安装mysql主从 启动主库: 1.docker run --name master -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5 ...

  10. spring动态添加bean

    不知道大家想过没有,我们使用mybatis的时候只要写接口和配置上一个sql语句就可以了,单从代码的角度来看,这是不合理的. 所以我们通常在service里面注入的mapper它其实是一个代理对象 ​ ...