「OC」探索 KVC 的基础与应用

「OC」KVC的初步学习

文章目录

  • 「OC」KVC的初步学习
    • 前言
    • 介绍
      • KVC的相关方法
      • key和keyPath的区别
      • KVC的工作原理
        • KVO的`setValue:forKey`原理
        • KVO的`ValueforKey`原理
      • 在集合之中KVC的用法
        • 1. `mutableArrayValueForKey:` 和 `mutableArrayValueForKeyPath:`
        • 2. `mutableSetValueForKey:` 和 `mutableSetValueForKeyPath:`
        • 3. `mutableOrderedSetValueForKey:` 和 `mutableOrderedSetValueForKeyPath:`
      • KVC的操作符
      • 如何抛出异常
      • 1. `- (nullable id)valueForUndefinedKey:(NSString *)key;`
      • 2. `- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;`
    • 参考文章

前言

在我们前面总结了五大传值方法,其中在KVO之中,我们是用 observeValueForKeyPath:ofObject:change:context:的方法实现对对象的属性进行监听的,其中我们想要对属性监听需要我们用到一个KeyPath的参数,去找到监听对象之中与KeyPath名字相同的对应属性。KVC和KVO有些相似,KVC需要使用键值对去直接访问对应的属性

介绍

KVC的相关方法

KVC(Key-value coding)键值编码,指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值而不需要调用明确的存取方法。我们可以不使用getter/setter的方法间接访问对象当中的属性。这个间接,延伸来说就是可以破坏属性之中只读的特性,也可以直接访问到类之中的私有属性,一定程度上使用KVC是会破坏程序的封装性。

以下是KVC的使用方法

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

点击进入任意一个方法,我们可以看到

image-20240920114044998

这几个方法全都是在NSObject当中的NSKeyValueCodin分类写的,所以对于所有继承于NSObject之中的所有OC对象来说,都可以使用KVC的方法。

key和keyPath的区别

  • key(键)key 是一个字符串,用于标识对象中的属性。通过 valueForKey:setValue:forKey: 这样的方法,可以使用 key 来访问或设置对象的属性值。
  • keyPath(键路径)keyPath 是由多个 key 连接而成的路径,用于访问对象的嵌套属性。通过 valueForKeyPath:setValue:forKeyPath: 这样的方法,可以沿着路径访问嵌套属性(即访问对象属性之中的属性)。

以下是代码示例

#import "ViewController.h"@interface Address : NSObject@property (nonatomic, strong) NSString *city;@end@interface Person : NSObject@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, strong) Address *address;@end@implementation Person
@end@implementation Address
@end@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];Person *person = [[Person alloc] init];[person setValue:@"bb" forKey:@"name"];[person setValue:@30 forKey:@"isAge"];Address *address = [[Address alloc] init];[address setValue:@"Xi'An" forKey:@"city"];[person setValue:address forKey:@"address"];// 使用 key 访问属性NSString *name = [person valueForKey:@"name"];NSNumber *age = [person valueForKey:@"age"];// 使用 keyPath 访问嵌套属性NSString *city = [person valueForKeyPath:@"address.city"];NSLog(@"%@ %@",name, age);NSLog(@"%@", city);
}@end

image-20240920121759817

KVC的工作原理

这里借用大佬博客之中的图片

KVO的setValue:forKey原理

在这里插入图片描述

使用以下代码进行实验

-(void)setAge:(NSNumber *)age {NSLog(@"1");_age = age;
}

image-20240920212020720

通过实验我发现,在用@property创建属性的时候,使用KVC的时候似乎不会对_setKey进行查找,另外一个有趣的点,如果我们在属性之中重写属性方法的名称,如下

@property (nonatomic, strong, setter = makeName:) NSString *name;

然后像上面一下写一个setter方法,那么KVC不会检测到这个重写后到setter,会直接执行后面的步骤

-(void)makeName:(NSString *)name {_name = name;NSLog(@"1");
}

接着,如果找不到对应的setter方法的话,就要执行accessInstanceVariablesDirectly这个方法,当这个方法返回 YES 时,KVC 将会优先访问对象的实例变量;返回 NO 时,KVC直接调用setValue:forUndefinedKey:,抛出异常

KVC在得到为YES的值之后,就会直接对寻找成员变量对其进行赋值,依照KeyisKey的顺序进行查找。

KVO的ValueforKey原理

在这里插入图片描述

这个方法和上面那个方法类似,只不过这个方法为getter,探究的过程和上面的方法类似,这里不多做赘述直接给出总结

  • 1、按照getKey,key,isKey,_key的顺序查找成员方法,如果找到直接调用取值
  • 2、如果没有找到,查看accessInstanceVariablesDirectly的返回值
  • 返回值为YES,按照_Key,_isKey,Key,isKey的顺序查找成员变量,如果找到,直接取值,如果没有找到,调用setValue:forUndefinedKey:,抛出异常
  • 返回NO,直接调用setValue:forUndefinedKey:,抛出异常

在集合之中KVC的用法

在我们遇上对集合使用KVC的时候,可以用以下方法

- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath- (NSMutableSet *)mutableSetValueForKey:(NSString *)key
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key 
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath

这些方法就是使用KVC是获取对象之中的集合属性,以下是简单示例

1. mutableArrayValueForKey:mutableArrayValueForKeyPath:
// 获取可变数组对象
NSMutableArray *mutableArray = [object mutableArrayValueForKey:@"arrayProperty"];// 使用 Key-Value Path 获取可变数组对象
NSMutableArray *nestedMutableArray = [object mutableArrayValueForKeyPath:@"nestedObject.arrayProperty"];
2. mutableSetValueForKey:mutableSetValueForKeyPath:
// 获取可变集合对象
NSMutableSet *mutableSet = [object mutableSetValueForKey:@"setProperty"];// 使用 Key-Value Path 获取可变集合对象
NSMutableSet *nestedMutableSet = [object mutableSetValueForKeyPath:@"nestedObject.setProperty"];
3. mutableOrderedSetValueForKey:mutableOrderedSetValueForKeyPath:
// 获取可变有序集合对象
NSMutableOrderedSet *mutableOrderedSet = [object mutableOrderedSetValueForKey:@"orderedSetProperty"];// 使用 Key-Value Path 获取可变有序集合对象
NSMutableOrderedSet *nestedMutableOrderedSet = [object mutableOrderedSetValueForKeyPath:@"nestedObject.orderedSetProperty"];

那么这些方法的运用场景是什么呢?根据大佬的博客,是和我们前面讲到KVO有些相关,因为我们单纯向可变集合当中添加元素,并不会使得数组的首地址出现任何改变,KVO无法对可变集合的改变进行监听,那么除了我们手动对KVO进行监听之外,我们就可以用上这个相对应的方法使用KVC进行监听。

使用- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath这个方法可以使得可变数组的地址发生改变,也就是完成一次深层拷贝。

在字典之中KVC的用法

- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;

用对字典类型使用KVC其实更多用在网络请求之中,因为网络请求的JSON数据是以字典的类型进行返回,有时候一个对象的属性有很多个就不太方便我们使用平时普通的赋值方法,太过于复杂了。我们对于Model类来说,用以下方式会更加方便

这个属性最常用到的地方就是字典转模型 例如我们有一个Student类,

@interface Student : NSObject
@property (nonatomic,assign) float height;
@property (nonatomic,assign) int age;
@property (nonatomic,strong) NSString *name;
@end

使用setValuesForKeysWithDictionary方法呢

Student *stu = [[Student alloc]init];
//在进行网络请求之后得到的数据
NSDictionary *dic = @{@"name":@"jack",@"height":@180,@"age":@10};
[stu setValuesForKeysWithDictionary:dic];

KVC的操作符

KVC可以调用相对应的操作符,像这样的函数共有5个@avg,@count,@max,@min,@sum。顾名思义,分别就是平均数,数组大小,最大值,最小值,总和,用法大致如下:

  1. @avg:计算集合中指定属性的平均值。
NSArray *numbers = @[@10, @20, @30, @40];
NSNumber *average = [numbers valueForKeyPath:@"@avg.self"];
NSLog(@"Average: %@", average);
  1. @count:计算集合中元素的数量。
NSArray *numbers = @[@10, @20, @30, @40];
NSNumber *count = [numbers valueForKeyPath:@"@count"];
NSLog(@"Count: %@", count);
  1. @max:计算集合中指定属性的最大值。
NSArray *numbers = @[@10, @20, @30, @40];
NSNumber *maxValue = [numbers valueForKeyPath:@"@max.self"];
NSLog(@"Max Value: %@", maxValue);
  1. @min:计算集合中指定属性的最小值。
NSArray *numbers = @[@10, @20, @30, @40];
NSNumber *minValue = [numbers valueForKeyPath:@"@min.self"];
NSLog(@"Min Value: %@", minValue);
  1. @sum:计算集合中指定属性的总和。
NSArray *numbers = @[@10, @20, @30, @40];
NSNumber *sum = [numbers valueForKeyPath:@"@sum.self"];
NSLog(@"Sum: %@", sum);

如何抛出异常

前面我们说到,如果KVC找不到对应的属性的话,KVC就会进行异常抛出。

在异常发生时会抛出一个NSUndefinedKeyException的异常,并且应用程序Crash。我们可以重写下面两个方法,根据业务需求合理的处理KVC导致的异常。

- (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
- (void)setNilValueForKey:(NSString *)key;

其中重写这两个方法,在key值不存在的时候,会走下面方法,而不会异常抛出

- (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

在 Objective-C 中,这些方法是用于处理对象的未定义键(Undefined Key)的情况的方法。通常,当您尝试访问或设置一个对象中不存在的键时,系统会调用这些方法。以下是这些方法的简要说明以及如何操作它们:

1. - (nullable id)valueForUndefinedKey:(NSString *)key;

这个方法在尝试获取对象中不存在的键的值时被调用。我们可以通过实现这个方法来自定义对象对未定义键的行为。

- (nullable id)valueForUndefinedKey:(NSString *)key {if ([key isEqualToString:@"undefinedKey"]) {// 返回一个默认值或者处理逻辑return @"Default Value";} else {// 调用父类的默认行为return [super valueForUndefinedKey:key];}
}

2. - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

这个方法在尝试为对象中不存在的键设置值时被调用。我们可以实现这个方法来定义对象对未定义键设置值的行为。

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key {if ([key isEqualToString:@"undefinedKey"]) {// 自定义处理逻辑,例如忽略或记录警告NSLog(@"Attempted to set a value for an undefined key: %@", key);} else {// 调用父类的默认行为[super setValue:value forUndefinedKey:key];}
}

参考文章

KVC

KVC基本原理和用法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/435505.html

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

相关文章

Java项目实战II基于Java+Spring Boot+MySQL的智能物流管理系统(文档+源码+数据库)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着电子商务的蓬勃发展&#xff0c;物流行业迎来了前所未有的挑战与机遇。传统物流管理方式在应对海…

PDCA优化任务流程

这里写目录标题 一、背景二、PDCA重要性与必要性概念PDCA循环的重要性 三、PDCA分析这次任务的执行任务描述分析原因&#xff1a;结合PDCA分析&#xff1a;提高办法&#xff1a; 四、总结 一、背景 汇报任务完成情况&#xff0c;未提交实际成果。 本次总结旨在通过PDCA循环的视…

二值图像的面积求取的两种方法及MATLAB实现

一、引言 面积在数字图像处理中经常用到&#xff0c;在MATLAB中&#xff0c;计算二值图像的面积通常可以通过两种主要方法实现&#xff1a;遍历法和直接利用bwarea函数。下面将分别介绍这两种方法的原理和相应的MATLAB代码示例。 二、遍历法计算二值图像面积的原理和MATLAB代码…

如何创建虚拟环境并实现目标检测及验证能否GPU加速

创建虚拟环境&#xff1a; 先创建一个虚拟python环境&#xff0c;敲如下代码 然后再到该虚拟环境里面安装自己想要的包 激活虚拟环境 然后再聚类训练这些 验证GPU加速 阿里源 pip install torch torchvision -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mir…

Appinventor2 多屏幕之间如何共享过程?

先说结论&#xff1a;不能共享&#xff0c;但可以变通&#xff0c;这个问题上没有完美方案&#xff01; Appinventor2 多屏幕之间如何共享过程&#xff1f;或者说如何跨屏幕调用其他屏幕的过程&#xff1f; 相信有很多人有过这样的问题&#xff0c;但是目前来看每个屏幕都是独…

Linux下驱动开发实例

驱动开发 驱动与硬件的分离 在传统的嵌入式系统开发中&#xff0c;硬件信息往往是直接硬编码在驱动代码中的。这样做的问题是&#xff0c;当硬件发生变化时&#xff0c;比如增加或更换设备&#xff0c;就需要修改驱动程序的代码&#xff0c;这会导致维护成本非常高。因此&…

机器学习周报(9.23-9.29)

文章目录 摘要Abstract1 自监督学习&#xff08;Self-Supervised Learning&#xff09;1.1 BERT1.1.1 Masking Input1.1.2 Next Sentence Prediction1.1.3 BERT的使用方式 1.2 Why does BERT work?1.3 Multi-lingual BERT 2 pytorch中tensor相关函数学习使用2.1 张量拼接与拆分…

4G模组SIM卡电路很简单,但也要注意这些坑

上次水SIM卡相关的文章&#xff0c;还是上一次&#xff1b; 上一篇文章里吹牛说&#xff0c;跟SIM卡相关的问题还有很多&#xff0c;目的是为下一篇文章埋下伏笔&#xff1b;伏笔埋是埋下了&#xff0c;但如果债老是不还&#xff0c;心里的石头就总悬着&#xff0c;搞不好老板…

MAC的几个常见的快捷方式

1.mac 查看图片好的方式 默认查看图片的方式无法直接切换上一张下一张 解决方法&#xff1a; 1.&#xff08;最好的方法&#xff09;选中图片直接按空格&#xff0c;进入快速预览图片 2.就是全部选中然后打开&#xff0c;但是说实话有点奇怪&#xff0c;而且很占内存 3.直接显示…

Linux 信号捕捉

我们知道信号的处理不是即时的&#xff0c;进程在合适的时机才会处理信号&#xff0c;而这个时机就比如从内核态返回用户态。 1. 用户态与内核态 在操作系统中&#xff0c;用户态&#xff08;User Mode&#xff09;和内核态&#xff08;Kernel Mode&#xff09;是两种不同的C…

安卓主板_MTK4G/5G音视频记录仪整机及方案定制

音视频记录仪方案&#xff0c;采用联发科MT6877平台八核2* A78 6* A55主频高达2.4GHz, 具有高能低耗特性&#xff0c;搭载Android 12.0智能操作系统&#xff0c;可选4GB32GB/6GB128GB内存&#xff0c;运行流畅。主板集成NFC、双摄像头、防抖以及多种无线数据连接&#xff0c;支…

如何在 Kubernetes 上部署和配置开源数据集成平台 Airbyte?

在 Kubernetes 上部署和配置 Airbyte 是一个复杂但非常有价值的过程&#xff0c;特别是对于需要强大数据集成和数据处理能力的企业或团队。Airbyte 是一个开源的数据集成平台&#xff0c;允许用户从各种来源提取数据并加载到目标存储中。其强大的插件系统支持多种数据源与目标&…

新能源汽车储充机器人:能源高效与智能调度

新能源汽车储充机器人&#xff1a;开启能源高效利用与智能调度的未来之门 随着全球能源危机的日益加剧和环境污染问题的不断恶化&#xff0c;新能源汽车成为了未来交通领域的重要发展方向。然而&#xff0c;新能源汽车的普及不仅需要解决电池技术的瓶颈&#xff0c;还需要构建一…

labview更换操作系统后打开原VI闪退

labview更换操作系统后打开原VI闪退 问题描述&#xff1a; Windows11由家庭版更换为专业版后&#xff0c;重新安装labview2021&#xff0c;打开原来的项目&#xff0c;项目管理器可以正常打开&#xff0c;但是打开VI却闪退&#xff0c;并报错如下 出现这种原因主要是labview在…

通信工程学习:什么是LAN局域网、MAN城域网、WAN广域网

LAN局域网、MAN城域网、WAN广域网 LAN&#xff08;Local Area Network&#xff0c;局域网&#xff09;、MAN&#xff08;Metropolitan Area Network&#xff0c;城域网&#xff09;和WAN&#xff08;Wide Area Network&#xff0c;广域网&#xff09;是计算机网络中根据覆盖范围…

vue组合式api

一、ref&#xff08;基本类型数据&#xff0c;对象类型数据&#xff09; 1.作用&#xff1a;定义响应式变量 2.语法&#xff1a;let xxx ref(初始值) 3.返回值&#xff1a;一个RefImpl的实例对象&#xff0c;简称ref对象&#xff0c;ref对象的value属性是响应式的。 4.注意…

【MySQL】视图、用户和权限管理

目录 视图创建视图数据修改影响删除视图视图优点 用户和权限管理查看当前的数据库拥有用户信息创建用户修改密码删除用户权限授权回收权限 视图 视图就是相当于创建一个表&#xff0c;将查询到的结果集给存储起来。像使用复杂的多表查询查询到的结果集就不可以对结果集操作。而…

2024/9/29周报

文章目录 摘要Abstract污水处理工艺流程整体介绍粗格栅细格栅曝气沉砂池提升泵房峰谷平策略 初沉池&#xff08;一级处理&#xff09;工作原理运行管理 氧化沟生化池&#xff08;二级处理&#xff09;二沉池工作原理运行参数 高效沉淀池功能与特点工作原理 深度处理&#xff08…

Coursera_ Algorithms I 学习笔记:Module_3_Analysis_of_Algorithm_Introduction

Coursera_ Algorithms I 学习笔记&#xff1a;Module_3_Analysis_of_Algorithm_Introduction scientific method applied to analysis of algorithms data analysis log-log plot doubling hypothesis experimental alogrithmics System independent effectsSystem dependen…

Electron 主进程与渲染进程、预加载preload.js

在 Electron 中&#xff0c;主要控制两类进程&#xff1a; 主进程 、 渲染进程 。 Electron 应⽤的结构如下图&#xff1a; 如果需要更深入的了解electron进程&#xff0c;可以访问官网 流程模型 文档。 主进程 每个 Electron 应用都有一个单一的主进程&#xff0c;作为应用…