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

news2024/11/18 12:22:30

「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.coloradmin.cn/o/2177873.html

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

相关文章

【源码+文档+调试讲解】无人超市系统python

摘 要 随着科技的不断进步&#xff0c;无人超市成为了零售行业的新兴趋势。无人超市管理系统是支撑这一新型商业模式的关键软件基础设施。该系统采用python技术和MySQL数据库技术以及Django框架进行开发。通过高度自动化和智能化的方式&#xff0c;允许消费者在没有收银员的情…

WordPress LearnPress插件 SQL注入复现(CVE-2024-8522)

0x01 产品描述&#xff1a; LearnPress 是一款功能强大的 WordPress LMS&#xff08;学习管理系统&#xff09;插件&#xff0c;适用于创建和销售在线课程。凭借其直观的界面和丰富的功能&#xff0c;无论您是否具备编程背景&#xff0c;都能轻松搭建起在线教育网站。学会如何使…

【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(三)

文章目录 一、商品管理1、需求说明2、生成基础代码&#xff08;1&#xff09;创建目录菜单&#xff08;2&#xff09;配置代码生成信息&#xff08;3&#xff09;下载代码并导入项目 3、商品类型改造&#xff08;1&#xff09;基础页面 4、商品管理改造&#xff08;1&#xff0…

【YOLO目标检测车牌数据集】共10000张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;10000&#xff08;2000张绿牌、8000张蓝牌&#xff09; 标注数量(txt文件个数)&#xff1a;10000 标注类别数&#xff1a;1 标注类别名称&#xff1a;licence 数据集下载&#xff1a;车牌数据…

docker 部署 Seatunnel 和 Seatunnel Web

docker 部署 Seatunnel 和 Seatunnel Web 说明&#xff1a; 部署方式前置条件&#xff0c;已经在宿主机上运行成功运行文件采用挂载宿主机目录的方式部署SeaTunnel Engine 采用的是混合模式集群 编写Dockerfile并打包镜像 Seatunnel FROM openjdk:8 WORKDIR /opt/seatunne…

在github上,如何只下载选中的文件?

GitHub官方不直接支持下载子目录&#xff0c;但可以使用特定的第三方工具或脚本来实现这一需求。 总而言之一句话&#xff1a;需要下载插件&#xff01;&#xff01;&#xff01;具体实操步骤如下&#xff1a; 1.打开谷歌浏览器右上角的管理扩展程序&#xff1a; 2.搜索GitZi…

NLP任务之预测最后一个词

目录 1.加载预训练模型 2 从本地加载数据集 3.数据集处理 4.下游任务模型 5.测试代码 6.训练代码 7.保存训练好的模型 8. 加载 保存的模型 1.加载预训练模型 #加载预训练模型 from transformers import AutoTokenizer#预训练模型&#xff1a;distilgpt2 #use_fast…

《无机杀手》制作团队选择Blender的原因分析

《无机杀手》&#xff08;Murder Drones&#xff09;是一部备受欢迎的动画短片&#xff0c;其制作团队选择使用Blender软件进行制作&#xff0c;这一选择背后有着多方面的原因。【成都渲染101--blender渲染农场邀请码6666提供文案参考】 开源且免费 Blender是一个开源且免费的…

什么是数字化转型?数字化转型对企业有哪些优势?

一、什么是数字化转型&#xff1f; 定义&#xff1a; 数字化转型是指企业或组织将传统业务转化为数字化业务&#xff0c;利用人工智能、大数据、云计算、区块链、5G等数字技术提升业务效率和质量的过程。通俗来说&#xff0c;就是将数字技术应用到企业的各个方面&#xff0c;…

贝锐蒲公英网盘首发,秒建私有云,高速远程访问

虽然公共网盘带来了不少便利&#xff0c;但是大家对隐私泄露和重要数据泄密的担忧也随之增加。如果想要确保数据安全&#xff0c;自建私有云似乎是一条出路&#xff0c;然而面对搭建私有云的复杂步骤&#xff0c;许多人感到力不从心&#xff0c;NAS设备的成本也往往让人望而却步…

【MySQL】数据库中的内置函数

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 目录 函数 日期函数 字符串函数 数学函数 ​编辑 其它函数 MySQL数据库提供了大量的内置函数&#xff0c;这些函数可以帮助你执行各种操作&#xff0c;如字符串处理、数值计算、日期和时间处理等&#xff01; 函数…

云计算Openstack Keystone

OpenStack Keystone是OpenStack平台中的一个核心组件&#xff0c;主要负责身份认证和授权管理服务。以下是关于OpenStack Keystone的详细介绍&#xff1a; 一、作用 身份认证&#xff1a;Keystone为OpenStack平台提供统一的身份认证服务&#xff0c;管理所有用户&#xff08;…

ElasticSearch系列:【Win10环境(版本8.11.1) 】elasticsearch+kibana纪实

一、环境 安装环境&#xff1a;win10 JDK&#xff1a;1.8 elasticsearch&#xff1a;8.11.1 kibana&#xff1a;8.11.1 下载地址1&#xff08;elasticsearchkibana&#xff09;&#xff1a;Past Releases of Elastic Stack Software | Elastic i下载地址2&#xff08;k分…

RS HMP4040 直流电源

R&S HMP404 直流电源 苏州新利通仪器仪表 产品综述 单台仪器中最多四个通道 R&SHMP4000 直流电源具有三个或四个输出通道&#xff0c;每个通道的输出电流高达 10 A&#xff0c;主要设计用于工业应用&#xff0c;例如&#xff1a; -生产测试 -维护 -工程实验室 这些…

关于git分支冲突问题

什么是冲突 在Git中&#xff0c;冲突是指两个或多个开发者对同一文件统一部份进行了不同的修改&#xff0c;并且在合并这些修改时&#xff0c;Git无法自动确定应该采用哪种修改而产生的情况。 分支冲突 如何出现并解决 在一个版本时&#xff0c;有一个master分支&#xff0c…

JAVA甜蜜升级情侣专属扭蛋机游戏系统小程序源码

甜蜜升级&#xff01;情侣专属扭蛋机游戏系统&#xff0c;让爱更有趣&#x1f496; &#x1f389; 开篇&#xff1a;爱的游戏新玩法 在爱情的旅途中&#xff0c;我们总在寻找那些能让彼此心跳加速、笑容满面的瞬间。现在&#xff0c;“甜蜜升级情侣专属扭蛋机游戏系统”为你和…

用友畅捷通-TPlus FileUploadHandler.ashx 任意文件上传

0x01 产品描述&#xff1a; ‌用友畅捷通-TPlus‌是由用友集团成员企业畅捷通公司开发的一款企业级财务管理工具&#xff0c;旨在帮助企业实现财务管理的现代化和智能化。作为畅捷通旗下的核心产品&#xff0c;TPlus集成了财务核算、资金管理、预算控制等多项核心功能&#xff…

spring boot 项目中redis的使用,key=value值 如何用命令行来查询并设置值。

1、有一个老项目&#xff0c;用到了网易云信&#xff0c;然后这里面有一个AppKey&#xff0c;然后调用的时候要在header中加入这些标识&#xff0c;进行与服务器进行交互。 2、开发将其存在了redis中&#xff0c;一开始的时候&#xff0c;我们测试用的老的key&#xff0c;然后提…

结合创新!小波变换+注意力机制,实现100%分类准确率

小波变换是一种先进的信号分析技术&#xff0c;它擅长捕捉信号的局部特征&#xff0c;但有时可能会忽略数据中的关键信息。为了克服这一局限&#xff0c;我们引入了注意力机制&#xff0c;这一机制能够强化模型对数据重要部分的关注。通过将小波变换与注意力机制相结合&#xf…

SD2.0 Specification之CRC(Cyclic Redundancy Code)

文章目录 本文章主要讲解关于SD2.0中的CRC应用&#xff0c;其它基础概念和其它内容请参考以下文章。 SD2.0 Specification简述 CRC全称为Cyclic Redundancy Code&#xff0c;中文名称是循环冗余校验&#xff0c;该方法通过附加冗余数据来保证数据的完整性&#xff0c;即用于检…