iOS开发基础14-KVC的应用与底层逻辑
在 iOS 开发中,Key-Value Coding
(KVC) 是一种十分强大的访问和修改对象属性的技术。通过 KVC,我们可以在运行时以字符串的形式直接访问属性,从而更灵活地操作对象。本文将详细介绍如何使用 KVC 进行数据的存取、字典转模型、模型转字典,以及一些高级应用。
一、KVC 简介
KVC 是一个非正式协议,它允许通过字符串键(Key)来访问对象的属性。相对于直接调用 setter 和 getter 方法,KVC 提供了一种更为动态的方式来操作对象的属性值。这对于例如字典与模型之间的转换,特别有用。
二、KVC 存数据
1. 基本属性的存取
我们定义一个 Person
类以及一个 Dog
类,用于演示 KVC 的使用。
Person.h
#import <Foundation/Foundation.h>
@class Dog;
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) double money;
@property (nonatomic, strong) Dog *dog;
@end
Person.m
#import "Person.h"
@implementation Person
{
@private
int _age;
}
- (void)say {
NSLog(@"age = %i", _age);
}
@end
Dog.h
#import <Foundation/Foundation.h>
@interface Dog : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) double price;
@end
Dog.m
#import "Dog.h"
@implementation Dog
@end
2. 使用 KVC 存数据
基本属性赋值
我们可以通过 KVC 来为 Person
对象的属性赋值。
Person *p = [[Person alloc] init];
// 使用 KVC 为基本属性赋值
[p setValue:@"lmj" forKey:@"name"];
[p setValue:@(668.0) forKey:@"money"];
多层赋值
对于嵌套对象的属性,我们可以使用 setValue:forKeyPath:
方法来进行赋值。
p.dog = [[Dog alloc] init];
[p setValue:@"xiaoqiang" forKeyPath:@"dog.name"];
[p setValue:@(110.0) forKeyPath:@"dog.price"];
给私有成员变量赋值
KVC 甚至可以突破 @private
修饰符的限制,直接访问私有成员变量。
[p setValue:@(30) forKey:@"_age"];
[p say]; // age = 30
字典转模型
KVC 还可以用于字典转模型,通过 setValuesForKeysWithDictionary:
方法可以将字典中的值赋予对象对应的属性。
NSDictionary *dict = @{
@"name": @"xxx",
@"money": @(998.1),
@"dog": @{ @"name": @"wangcai", @"price": @(110.0) }
};
// 使用 KVC 进行字典转模型
[p setValuesForKeysWithDictionary:dict];
NSLog(@"name = %@, money = %f", p.name, p.money); // getter
三、KVC 取数据
使用 KVC,我们不仅可以设置属性,还可以获取属性值。
1. 获取单个值
使用 valueForKey:
获取单个属性值。
NSString *name = [p valueForKey:@"name"];
double money = [[p valueForKey:@"money"] doubleValue];
NSLog(@"name = %@, money = %f", name, money);
2. 多层获取值
对于嵌套对象的属性,可以使用 valueForKeyPath:
方法。
NSString *dogName = [p valueForKeyPath:@"dog.name"];
NSLog(@"dogName = %@", dogName);
3. 模型转字典
通过 dictionaryWithValuesForKeys:
方法将对象转换为字典。
NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name", @"money"]];
NSLog(@"dict = %@", dict);
4. 获取数组中对象的值
如果数组中的元素都是相同类型的对象,可以使用 KVC 获取所有对象的某个属性值。
Person *p1 = [[Person alloc] init]; p1.name = @"zs"; p1.money = 111;
Person *p2 = [[Person alloc] init]; p2.name = @"ls"; p2.money = 222;
Person *p3 = [[Person alloc] init]; p3.name = @"ww"; p3.money = 666;
NSArray *arr = @[p1, p2, p3];
NSArray *names = [arr valueForKeyPath:@"name"];
NSLog(@"names = %@", names);
5. KVC 运算符
KVC 支持一些简单的集合运算符,比如获取数组中某个属性的平均值、最大值、最小值等。
// 平均值
id avgMoney = [arr valueForKeyPath:@"@avg.money"];
// 最大值
id maxMoney = [arr valueForKeyPath:@"@max.money"];
// 最小值
id minMoney = [arr valueForKeyPath:@"@min.money"];
NSLog(@"avgMoney = %@, maxMoney = %@, minMoney = %@", avgMoney, maxMoney, minMoney);
四、KVC 底层逻辑分析
1. valueForKey: 和setValue:forKey:
-
valueForKey:
方法内部执行流程:- 查找同名的 getter 方法。
- 查找同名的带下划线 _ 属性。
- 查找
accessInstanceVariablesDirectly
方法,如果返回 YES,则直接访问同名或带下划线的实例变量。 - 如果上述查找均失败,则执行
valueForUndefinedKey:
方法。
-
setValue:forKey:
方法内部执行流程:- 查找同名的 setter 方法。
- 查找同名的带下划线 _ 属性。
- 查找
accessInstanceVariablesDirectly
方法,如果返回 YES,则直接访问同名或带下划线的实例变量。 - 如果上述查找均失败,则执行
setValue:forUndefinedKey:
方法。
2. Key-Value Observing (KVO) 交互
KVC 和 KVO 通常一起使用。当通过 KVC 修改属性时,属性的变更会触发 KVO 回调,从而允许响应式编程。
3. 字典转模型与模型转字典
通过 KVC,可以快速进行字典与模型之间的数据转换,大大简化了数据的过滤和处理流程。
总结:
KVC 作为一种灵活强大、高效便捷的编程技术,通过提供统一的接口实现对于对象属性的访问与操作,使得开发过程中实现模型和视图之间的数据绑定变得更加轻松。此外,通过 KVC 方法内部流程和原理的深层分析,我们可以理解并合理利用这一特性,进一步提升代码的灵活性和通用性。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!