【iOS】KVC

文章目录

  • 前言
  • 一、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.mzph.cn/pingmian/6701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[粉丝问题] 主键使用自增ID还是UUID?

推荐使用自增ID&#xff0c;不要使用UUID。 因为在InnoDB存储引擎中&#xff0c;主键索引是作为聚簇索引存在的&#xff0c;也就是说&#xff0c;主键索引的B树叶子节点上存储了主键索引以及全部的数据(按照顺序)&#xff0c;如果主键索引是自增ID&#xff0c;那么只需要不断向…

JavaScript中的DOM和BOM

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f4af;Web API&#x1f340;1 API的概念&#x1f340;2 Web API的概念…

【C++ | 关键字】C++ 关键字介绍

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-05-04 0…

手摸手,带你用vue撸后台

前言 说好的教程终于来了&#xff0c;第一篇文章主要来说一说在开始写实际业务代码之前的一些准备工作吧&#xff0c;但这里不会教你 webpack 的基础配置&#xff0c;热更新原理是什么&#xff0c;webpack速度优化等等&#xff0c;有需求的请自行 google&#xff0c;相关文章已…

【JDBC】Apache DbUtils工具类使用

1 简介 Commons DbUtils是Apache 组织提供的一个对]DBC进行简单封装的开源工具类库&#xff0c;简化JDBC应用程序的开发&#xff0c;同时也不会影响程序的性能&#xff0c;是一个小巧简单实用的工具。对于数据表的读操作&#xff0c;可以把结果转换成List、Array、Set等java集…

【C++】详解STL的容器之一:list

目录 简介 初识list 模型 list容器的优缺点 list的迭代器 常用接口介绍 获取迭代器 begin end empty size front back insert push_front pop_front push_back pop_back clear 源代码思路 节点设计 迭代器的设计 list的设计 begin() end() 空构造 ins…

代码随想录35期Day30-Java

Day30题目 写在前面 五一收假&#xff0c;并且这三道题都是选做&#xff0c;明天看一下吧。 LeetCode332.重新安排行程 &#xff1a;todo LeetCode51. N皇后 class Solution {List<String> path new ArrayList<>();List<List<String>> res new …

使用360绿色清理工具释放磁盘空间

缘起&#xff1a; 配置差的电脑&#xff0c;在尝试安装360安全卫士时&#xff0c;它变得非常卡顿&#xff0c;无法正常使用。我安装360的初衷其实是想定期清理C盘的空间&#xff0c;以优化电脑的性能。 经过一番探索&#xff0c;发现了一个方法&#xff0c;可以单独提取出360…

Mybatis扩展

1. Myabtis注解开发 ​ 这几年来注解开发越来越流行&#xff0c;Mybatis也可以使用注解开发方式&#xff0c;这样我们就可以减少编写Mapper映射文件了。我们先围绕一些基本的CRUD来学习&#xff0c;再学习复杂映射多表操作。 1.1 常见注解 Insert&#xff1a;实现新增 Up…

Docker镜像的创建和Dockerfile

一. Docker 镜像的创建&#xff1a; 1.基于现有镜像创建: &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改docker run -it --name web3 centos:7 /bin/bash #启动容器​yum install -y epel-release #安装epel源yum install -y nginx #安…

物联网小demo

机智云生成代码 具体参考之前的文章 初始化 ADC用来使用光敏电阻 连续采样开启 采样的周期调高 定时器 定时器1用来实现延时 为了只用温湿度模块DHT11 定时器4用来和51进行交互 实现定时的发送和检测心跳信号 IIC 用来使用oled屏幕 USART 串口1和串口2是机智云自己…

ROS是什么

一、ROS通信机制--松耦合分布式通信 1、核心概念 ①节点&#xff08;node&#xff09;---软件模块 ②节点管理器&#xff08;ROS master&#xff09;---控制中心&#xff0c;提供参数管理 ③话题&#xff08;topic&#xff09;---异步通信机制&#xff0c;传输消息&#xf…

【设计模式】13、template 模板模式

文章目录 十三、template 模板模式13.1 ppl13.1.1 目录层级13.1.2 ppl_test.go13.1.3 ppl.go13.1.4 llm_ppl.go13.1.5 ocr_ppl.go 十三、template 模板模式 https://refactoringguru.cn/design-patterns/template-method 如果是一套标准流程, 但有多种实现, 可以用 template …

Leetcode 3132. Find the Integer Added to Array II

Leetcode 3132. Find the Integer Added to Array II 1. 解题思路2. 代码实现 题目链接&#xff1a;3132. Find the Integer Added to Array II 1. 解题思路 这一题由于是统一增加了一个位移&#xff0c;然后再删除了两个元素&#xff0c;因此我们将两个数组进行排序&#x…

MySQL入门学习-使用数据库.创建和删除数据库

MySQL是一种流行的关系型数据库管理系统&#xff0c;可以用于存储和管理大量数据。在MySQL中&#xff0c;可以通过创建和删除数据库来组织和管理数据。 一、关于MySQL中创建和删除数据库的概述&#xff1a; 1. 创建数据库&#xff1a; 在MySQL中&#xff0c;可以使用CREATE …

Py脚本_文件分类

最近发现通过Edge和chrome或者其他浏览器下载的文件都存放在一个地方就很繁琐&#xff0c;于是翻找以前的脚本来归纳这些文件&#xff0c;虽然有IDM下载独有会自动分类&#xff0c;但是相信很多同学都在一个文件里找文件&#xff0c;这次就写个Py脚本来实现这个功能。 # -*- c…

XML:基础

一、语法 基本结构&#xff1a; 实例一&#xff1a; <?xml version"1.0" encoding"ISO-8859-1"?> <note data"2008/08/08"> <to>George</to> <from>John</from> <heading>Reminder</heading&…

深入理解Java中的Lambda表达式

Java 8引入的Lambda表达式&#xff08;或称匿名函数&#xff09;是一种简洁优雅的语法&#xff0c;极大简化了开发者编写代码的方式。它可以作为参数传递给方法或赋值给变量&#xff0c;适用于简化代码的场景。本文将详细介绍Lambda表达式的使用&#xff0c;并结合代码实例进行…

C语言 void 指针就是空指针吗?它有什么作⽤?

一、问题 这是⼀个在⾯试时很容易出现的问题&#xff0c;但是也是很多⼈混淆的问题&#xff0c;这个问题如何回答&#xff1f; 二、解答 void 指针⼀般称为通⽤指针&#xff0c;要与空指针严格区分。void 指针⽤于指向⼀个不属于任 何类型的对象&#xff0c;所以 void 指针称为…

k8s集群安装

目录 部署步骤概览 1、基础环境部署 2、docker环境部署 3、配置k8s集群 4、集群初始化 5、安装dashboard软件 写在前面&#xff1a;本文安装单点master多node的k8s集群&#xff0c;主要用于k8s学习或k8s环境测试&#xff1b;部署的是1.23版本&#xff0c;在1.24版本起&am…