【iOS】KVC

server/2024/11/25 15:57:48/

文章目录

  • 前言
  • 一、KVC常用方法
  • 二、key与keypath
    • 区别
    • key用法
    • keypath用法
  • 三、批量存值操作
  • 四、字典与模型相互转化
  • 五、KVC底层原理
    • KVC设值底层原理
    • KVC取值底层原理


前言

KVC的全称是Key-Value Coding,翻译成中文叫做键值编码

KVC提供了一种间接访问属性方法或成员变量的机制,允许通过字符串来访问对应的属性方法或成员变量

它是一个非正式的Protocol,提供一种机制来间接访问对象的属性,而不是通过调用Setter、Getter方法访问。KVO 就是基于 KVC 实现的关键技术之一

一、KVC常用方法

通过key 设值/取值

//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;//通过Key来设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;

通过keyPath (即路由)设值/取值

//通过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来设值                 
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  

其他方法

//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
+ (BOOL)accessInstanceVariablesDirectly;//KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;//如果Key不存在,且KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (nullable id)valueForUndefinedKey:(NSString *)key;//和上一个方法一样,但这个方法是设值。
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;

二、key与keypath

区别

key:只能接受当前类所具有的属性,不管是自己的,还是从父类继承过来的
keypath:除了能接受当前类的属性,还能接受当前类属性的属性,即可以接受关系链,然后进行深层访问

key用法

        People *t1 = [[People alloc] init];Address *t2 = [[Address alloc] init];t1.Ad = t2;[t1 setValue:@"顶针" forKey:@"name"];NSLog(@"%@", [t1 valueForKey:@"name"]);

输出:
在这里插入图片描述

keypath用法

在这里插入图片描述
输出:
在这里插入图片描述

三、批量存值操作

同样,也可以通过KVC进行批量操作,使用对象调用setValuesForKeysWithDictionary:方法时,可以传入一个包好keyvalue的字典进去,KVC可以将所有数据按照属性名和字典的key进行匹配,并将value给对象的属性赋值

        NSDictionary *dictionarySecond = @{@"name":@"顶针", @"age":@"11", @"sex":@"女"};People *t3 = [[People alloc] init];[t3 setValuesForKeysWithDictionary:dictionarySecond];NSLog(@"name = %@, age = %ld, sex = %@",t3.name, (long)t3.age, t3.sex);

在这里插入图片描述

四、字典与模型相互转化

如果model属性和dic不匹配,可以重写方法-(void)setValue:(id)value forUndefinedKey:(NSString *)key。
这一点后面会讲到

字典转模型

NSDictionary *dictionary = @{@"name":@"stu1", @"age":@66, @"sex":@"nv"};StudentModel *model = [[StudentModel alloc] init];[model setValuesForKeysWithDictionary:dictionary];NSLog(@"model.name:%@",model.name);NSLog(@"model.age:%@",model.age);NSLog(@"model.sex:%@",model.studentSex);

输出:
在这里插入图片描述
模型转字典

NSDictionary *tempModelDictionary = [model dictionaryWithValuesForKeys:@[@"name", @"age", @"studentSex"]];NSLog(@"tempModelDictionary : %@", tempModelDictionary);

输出:
在这里插入图片描述

五、KVC底层原理

KVC设值底层原理

在日常开发中,针对对象属性的赋值,一般有以下两种方式

  • 直接通过setter方法赋值
  • 通过KVC键值编码的相关API赋值
LGPerson *person = [[LGPerson alloc] init];
// 1、一般setter 方法
person.name      = @"CJL_哈哈";
// 2、KVC方式
[person setValue:@"CJL_嘻嘻" forKey:@"name"]; 

下面针对setValue:forKey进行底层原理探索

在这里,我们通过Key-Value Coding Programming Guide苹果官方文档来研究,针对设值流程,有如下说明

当调用setValue:forKey:设置属性value时,其底层的执行流程为

  • 【第一步】首先查找是否有这三种setter方法,按照查找顺序为set<Key>:-> _set<Key> -> setIs<Key>

如果有其中任意一个setter方法,则直接设置属性的value(主注意:key是指成员变量名,首字符大小写需要符合KVC的命名规范)

如果都没有则进入第二步

  • 【第二步】:如果没有第一步中的三个简单的setter方法,则查找accessInstanceVariablesDirectly是否返回YES

如果返回YES,则查找间接访问的实例变量进行赋值,查找顺序为:_<key> -> _is<Key> -> <key> -> is<Key>

如果找到其中任意一个实例变量,则赋值,如果都没有,则进入【第三步】

  • 【第三步】如果setter方法 或者 实例变量都没有找到,系统会执行该对象的setValue:forUndefinedKey:方法,默认抛出NSUndefinedKeyException类型的异常

综上所述,KVC通过 setValue:forKey: 方法设值的流程以设置LGPerson的对象person的属性name为例,如下图所示

在这里插入图片描述

KVC取值底层原理

当调用valueForKey:时,其底层的执行流程如下

  • 首先会按照getKey、key、isKey、_key的顺序查找方法,找到直接调用取值
  • 若未找到,则查看+ (BOOL)accessInstanceVariablesDirectly的返回值,若返回NO,则直接抛出NSUnknowKeyExpection异常;
  • 若返回的YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到则取值;
  • 找不到则调用valueForUndefinedKey:抛出NSUnknowKeyExpection异常;
    在这里插入图片描述

http://www.ppmy.cn/server/38339.html

相关文章

C++从入门到精通---模版

文章目录 泛型编程函数模版模版参数的匹配原则类模版类模版的定义格式类模版的实例化 总结 泛型编程 泛型编程是一种编程范式&#xff0c;旨在实现通用性和灵活性。它允许在编写代码时使用参数化类型&#xff0c;而不是具体的类型&#xff0c;从而使代码更加灵活和可重用。 在…

Linux进程——Linux进程间切换与命令行参数

前言&#xff1a;在上一篇了解完进程状态后&#xff0c;我们简单了解了进程优先级&#xff0c;然后遗留了一点内容&#xff0c;本篇我们就来研究进程间的切换&#xff0c;来理解上篇提到的并发。如果对进程优先级还有没理解的地方可以先阅读&#xff1a; Linux进程优先级 本篇…

值模板参数Value Template Parameters

模板通常使用类型作为参数&#xff0c;但它们也可以使用值。使用类型和可选名称声明一个值模板参数&#xff0c;方式与声明函数参数类似。值模板参数仅限于可以指定编译时常量的类型是bool、char、int等&#xff0c;但不允许使用浮点类型、字符串字面值和类。 #include <io…

LeetCode-hot100题解—Day6

原题链接&#xff1a;力扣热题-HOT100 我把刷题的顺序调整了一下&#xff0c;所以可以根据题号进行参考&#xff0c;题号和力扣上时对应的&#xff0c;那么接下来就开始刷题之旅吧~ 1-8题见LeetCode-hot100题解—Day1 9-16题见LeetCode-hot100题解—Day2 17-24题见LeetCode-hot…

单位档案寄存该怎么处理才好

处理单位档案寄存的方式可以根据实际情况来确定&#xff0c;以下是一些常见的处理方式&#xff1a; 1. 数字化存档&#xff1a;将单位档案进行数字化处理&#xff0c;通过扫描或拍照将文件转化为电子格式。这样可以方便查找和管理&#xff0c;减少纸质文件的存储量&#xff0c;…

【自动驾驶|毫米波雷达】初识毫米波雷达射频前端硬件

第一次更新&#xff1a;2024/5/4 目录 整体概述 混频器&#xff08;MIXER&#xff09; 低通滤波器&#xff08;LPF&#xff1a;Low-Pass filter&#xff09; 数模转换器&#xff08;ADC&#xff1a;Analog to Digital Converter&#xff09; 毫米波雷达功能框图 整体概述 完…

Spring中FactoryBean的作用和实现原理

Spring中FactoryBean的作用和实现原理 BeanFactory与FactoryBean&#xff0c;相信很多刚翻看Spring源码的同学跟我一样很好奇这俩货怎么长得这么像&#xff0c;分别都是干啥用的。 BeanFactory是Spring中Bean工厂的顶层接口&#xff0c;也是我们常说的SpringIOC容器&#xff…

CCF-CSP认证考试 202403-2 相似度计算 100分题解

更多 CSP 认证考试题目题解可以前往&#xff1a;CSP-CCF 认证考试真题题解 原题链接&#xff1a; 202403-2 相似度计算 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 题目背景 两个集合的 Jaccard 相似度定义为&#xff1a; S i m ( A , B ) ∣ A ∩ B ∣ ∣…