当前位置: 首页 > news >正文

【iOS】KVC 与 KVO 的基本了解与使用

文章目录

  • 前言
  • 一、KVC(Key-Value Coding)键值编码
    • 概念理解
    • 四个常用方法
    • key 与 keyPath 区别
    • KVC 查找与赋值流程
      • (1)查找 set 方法
      • (2)未找到 set 方法时
      • (3)如果都没找到
      • (4)特殊情况:给基本类型赋 nil
    • KVC 支持数值与结构体类型
    • KVC 验证机制
    • KVC 对集合的强大支持
      • 基本运算符:
      • 对象运算符:
    • KVC 操作字典
    • KVC 的典型应用场景
  • 二、KVO(Key-Value Observing)键值观察
    • 概念回顾
    • 实现步骤
    • 监听机制(内部原理)
    • KVO 与通知的区别
    • KVO 的优缺点
  • 三、KVC 与 KVO 的关系
  • 四、总结

前言

在 iOS 开发中,我们常用 Block、Delegate、通知等方式进行数据传递,这些传值方式在我前面博客都予以介绍过【iOS】多界面传值(五大传值方式)

但其实,Objective-C 还有一对我没有提到过的非常重要的两个东西:KVC(键值编码)KVO(键值观察)

简单介绍的话就是

  • KVC 允许我们通过字符串(key)访问属性;
  • KVO 允许我们自动监听属性值的变化。

它们一个负责“访问”,一个负责“观察”,是 Cocoa 动态机制的核心。

Cocoa即objective-c框架体系,如UIKit,Foundation,Appkit等

动态机制:程序的某些行为不是在编译时就固定好的,而是在运行时才决定的,总结如下:

  1. 变量在运行时才确定其真实类型
  2. 方法调用在运行时才决定调用哪个实现
  3. 类,方法甚至代码可以在运行时被加载或替换(kvo动态创建子类)

一、KVC(Key-Value Coding)键值编码

概念理解

KVC 是一种通过字符串键名来访问对象属性的机制,而不是直接调用 getter / setter。

例如我们平时这样写:

person.name = @"Tom";
NSLog(@"%@", person.name);

使用 KVC 可以写成:

[person setValue:@"Tom" forKey:@"name"];
NSLog(@"%@", [person valueForKey:@"name"]);

用字符串当作“钥匙”访问属性,无需明确调用方法。

KVC 是基于 NSObject 的一个扩展类别 —— NSKeyValueCoding 实现的。

因此,只要类继承自 NSObject,就可以天然支持 KVC。

四个常用方法

方法作用
setValue:forKey:通过 key 给属性赋值
setValue:forKeyPath:通过 keyPath给属性赋值
valueForKey:通过 key 获取属性
valueForKeyPath:通过 keyPath 获取属性

key 与 keyPath 区别

// key:只能访问当前对象的属性
[coffee setValue:@"100" forKey:@"price"];// keyPath:可访问关系链属性(例如嵌套对象)
[coffee setValue:@"white" forKeyPath:@"sonOfCoffee.color"];

keyPath 用点号(.)连接多个层级,是对嵌套对象的访问。

KVC 查找与赋值流程

KVC 的底层逻辑非常精细,赋值流程如下:

(1)查找 set 方法

按顺序查找以下方法:

  1. set:
  2. _set:

找到就直接调用

(2)未找到 set 方法时

会检查:

+ (BOOL)accessInstanceVariablesDirectly

如果返回 YES(默认值),则会依次查找成员变量:

_key → _isKey → key → isKey

找到后直接赋值。

(3)如果都没找到

调用:

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

系统默认会抛异常,但你可以重写它,避免崩溃:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {NSLog(@"未定义的Key:%@", key);
}

(4)特殊情况:给基本类型赋 nil

若 int、float 等类型被赋 nil,系统会调用:

- (void)setNilValueForKey:(NSString *)key

可重写该方法来安全处理:

- (void)setNilValueForKey:(NSString *)key {if ([key isEqualToString:@"age"]) age = 0;
}

KVC 支持数值与结构体类型

KVC 的 valueForKey: 总是返回 id 类型的对象。

如果访问的是数值或结构体,系统会自动封装成:

  • 数值类 → NSNumber
  • 结构体类 → NSValue

例如:

NSNumber *num = [NSNumber numberWithInt:10];
CGPoint point = CGPointMake(54, 45);
NSValue *value = [NSValue valueWithCGPoint:point];

通过 @encode() 还能让自定义结构体被封装:

NSValue *v = [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];

KVC 验证机制

KVC 还支持验证赋值是否合法:

- (BOOL)validateValue:(inout id *)ioValueforKey:(NSString *)inKeyerror:(NSError **)outError {if ([inKey isEqualToString:@"name"]) {NSString *name = *ioValue;if (name.length == 0) {*outError = [NSError errorWithDomain:@"MyDomain"code:1001userInfo:@{NSLocalizedDescriptionKey:@"名字不能为空"}];return NO;}}return YES;
}

KVC 对集合的强大支持

KVC 内置了许多集合运算符,可以直接在数组上操作对象属性。

基本运算符:

运算符含义
@count元素数量
@sum求和
@avg平均值
@max最大值
@min最小值
NSNumber *avg = [array valueForKeyPath:@"@avg.age"];
NSNumber *sum = [array valueForKeyPath:@"@sum.age"];

对象运算符:

运算符作用
@unionOfObjects不去重
@distinctUnionOfObjects去重
@unionOfArrays二维数组不去重
@distinctUnionOfArrays二维数组去重

示例:

NSArray *names = [array valueForKeyPath:@"@unionOfObjects.name"];

KVC 操作字典

KVC 可以轻松在对象和字典之间转换:

// 取值为字典
NSDictionary *dict = [user dictionaryWithValuesForKeys:@[@"name", @"age"]];// 用字典批量赋值
[user setValuesForKeysWithDictionary:@{@"name":@"Tom", @"age":@18}];

这在 Model <-> JSON 转换 中极为常见。

KVC 的典型应用场景

场景说明
动态访问属性运行时通过字符串操作属性
访问私有变量可用于调试或框架内部处理
Model-字典转换封装与解析 JSON
修改 UI 控件内部属性如 setValue:forKey:@“_placeholderLabel.textColor”
集合操作对模型数组进行聚合运算

二、KVO(Key-Value Observing)键值观察

概念回顾

KVO 是一种机制,让一个对象能在另一个对象属性变化时收到通知。

它常用于:

  • Model → Controller 数据同步;
  • Controller → View 自动更新;
  • Model 自身监听依赖属性变化。

实现步骤

// 注册观察
[account addObserver:selfforKeyPath:@"balance"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];// 回调方法
- (void)observeValueForKeyPath:(NSString *)keyPathofObject:(id)objectchange:(NSDictionary *)changecontext:(void *)context {NSLog(@"余额变化:%@", change);
}// 移除观察
[account removeObserver:self forKeyPath:@"balance"];

监听机制(内部原理)

官方文档中的解释:NSObject 在运行时会动态创建一个隐藏的子类,并重写被观察属性的 setter 方法来插入通知逻辑。

流程如下:

  1. 系统创建类:NSKVONotifying_Account
  2. 替换对象的 isa 指针
  3. 重写 setter:
willChangeValueForKey:
[super setBalance:newValue];
didChangeValueForKey:
  1. 调用观察者回调

KVO 与通知的区别

对比项KVONSNotification
触发时机属性值改变手动发布
是否自动触发
通知范围一对一一对多(全局)
基础实现依赖 KVC独立机制
用途监听对象属性广播事件消息

KVO 的优缺点

优点缺点
系统内置,几乎零代码语法繁琐
自动通知机制忘记移除崩溃
可观察依赖属性可读性差
可用于数据绑定难调试

三、KVC 与 KVO 的关系

可以这样理解:

对比KVCKVO
作用动态访问属性动态监听属性
触发方式调用 setter/gettersetter 内部触发通知
实现依赖NSObject(NSKeyValueCoding)NSObject(NSKeyValueObserving)
内部关系提供属性访问通道基于 KVC 的通道检测变化

KVO 是建立在 KVC 基础上的,所以也可以说没有 KVC,就没有 KVO。

四、总结

概念特点典型用途
KVC用字符串访问属性,支持私有变量和集合操作JSON 转 Model、调试
KVO自动监听属性变化并触发通知数据绑定、界面更新
联系KVO 内部依赖 KVC 的访问机制——

最后一句话概述就是,KVC 打开属性的大门,而当属性被改变时,KVO 会自动提醒我们

http://www.dtcms.com/a/506821.html

相关文章:

  • Day66 DHT11温湿度传感器驱动开发与单总线通信协议
  • 【代码管理】在本地使用github和gitee之后,可能存在冲突,导致再次提交代码时提示Couldn‘t connect to server
  • bash:**:pip:***python: 错误的解释器: 没有那个文件或目录
  • OpenCV(十二):Mat
  • iOS 智能应用开发实践:从模型集成到场景化交互
  • 更好的网站制作系统平台
  • 佛山市手机网站建设网站建设管理工作情况的通报
  • ThinkPad 安装 Ubuntu 系统教程
  • 《未来的 AI 操作系统(四)——AgentOS 的内核设计:调度、记忆与自我反思机制》
  • Platform Health Management 与 EXM/STM 的集成实现方式
  • lambda怎么遍历集合
  • 国外客户推广网站做羞羞事的网站
  • 安装好PySide6后如何找到Qt Designer(pyside6-designer.exe)可执行文件
  • EIT/ERT技术在机器人触觉传感的硬件及电路实现
  • h5游戏免费下载:公园停车
  • FPGA 49 ,Xilinx Vivado 软件术语解析(Vivado 界面常用英文字段详解,以及实际应用场景和注意事项 )
  • 自动化漏洞利用技术颠覆传统:微软生态暴露的攻防新变局
  • Annals of Neurology | EEG‘藏宝图’:用于脑电分类、聚类与预测的语义化低维流形
  • 中小学网站建设有什么好处管理系统软件开发
  • uniapp canvas实现手写签字功能(包括重签,撤回等按钮)
  • 大语言模型如何精准调用函数—— Function Calling 系统笔记
  • 商业智能BI 浅谈数据孤岛和数据分析的发展
  • Chrome 浏览器扩展图片 提取大师
  • Uniapp微信小程序开发:修改了数据,返回父页面时,父页面数据重新加载
  • etcd-问题-调优-监控
  • 【国内电子数据取证厂商龙信科技】手机版Chrome调试方法
  • 做企业网站要怎么设计方案信产部网站备案
  • 成都爱站网seo站长查询工具上海跨境电商网站制作
  • Linux网络编程:Socket编程TCP
  • 库周报 | 25亿融资!天兵科技冲刺IPO;双十一3D打印机价格战打响;拓竹、爱乐酷等发新品