kvc概念和核心方法

NSObject类中,有一个显示的类别名NSKeyValueCoding(缩写kvc),所以继承自NSObject的类都可以使用kvc,下面是kvc的4个主要方法:

- (nullable id)valueForKey:(NSString *)key;// 取类属性的值
- (void)setValue:(nullable id)value forKey:(NSString *)key;//给类属性设值
- (nullable id)valueForKeyPath:(NSString *)keyPath;//取类属性的属性的值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;// 给类属性的属性设值

对这4个方法的主要使用如下,可以分别通过key和keyPath来对类实例取值和设值;

// 家庭成员类
@interface Member : NSObject
@property(nonatomic, strong)NSString* role;
@end
@implementation Member
-(NSString*)desc {return [NSString stringWithFormat:@"member role:%@", _role];
}
@end
// 家族
@interface TomFamily : NSObject
@property(nonatomic,strong) NSString* familyName;
@property(nonatomic,strong) Member* member;
@end
@implementation TomFamily
-(void)show {NSLog(@"kvc存入成功");NSLog(@"familyName is: %@", _familyName);NSLog(@"member‘s role is: %@", [_member desc]);
}
@end、
int main(int argc, const char * argv[]) {@autoreleasepool {TomFamily* tomFamily = [[TomFamily alloc]init];Member* member = [[Member alloc]init];tomFamily.member = member;// kvc存入数据[tomFamily setValue:@"Tom家族" forKey:@"familyName"];[tomFamily setValue:@"father" forKeyPath:@"member.role"];// kvc取出数据[tomFamily show];NSLog(@"取出存入的数据: 家庭名称--%@, 家庭成员角色--%@", [tomFamily valueForKey:@"familyName"], [tomFamily valueForKeyPath:@"member.role"]);}return 0;
}

kvc进阶方法

一、 accessInstanceVariablesDirectly:是否链式查找_key,_iskey,key,iskey

+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索

实验如下,把familyName改成isFamilyName,看下能不能正常设置familyName值和取familyName值:

// 家族
@interface TomFamily : NSObject
{NSString* isFamilyName; // familyName => isFamilyName,也可以找到
}
@end
@implementation TomFamily
@end
int main(int argc, const char * argv[]) {@autoreleasepool {TomFamily* tomFamily = [[TomFamily alloc]init];[tomFamily setValue:@"Tom家族" forKey:@"familyName"];NSLog(@"取出存入的数据: 家庭名称--%@",[tomFamily valueForKey:@"familyName"]);}return 0;
}

输出如下:

取出存入的数据: 家庭名称--Tom家族

如果+ (BOOL)accessInstanceVariablesDirectly的返回值设置成NO,则找不到familyName就不会去尝试找isFamilyName,测试如下:

@interface TomFamily : NSObject
{NSString* isFamilyName;
}
@end
@implementation TomFamily
+ (BOOL)accessInstanceVariablesDirectly
{return NO; // 改成NO则编译报错,找不到familyName
}
@end
int main(int argc, const char * argv[]) {@autoreleasepool {TomFamily* tomFamily = [[TomFamily alloc]init];[tomFamily setValue:@"Tom家族" forKey:@"familyName"];NSLog(@"取出存入的数据: 家庭名称--%@",[tomFamily valueForKey:@"familyName"]);}return 0;
}

运行结果,报错

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<TomFamily 0x1004387c0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key familyName.'

二、validateValue:检验setter是否合法;

- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因

代码演示:验证familyName是否大于5个字符,否则不设值

@interface TomFamily : NSObject
{NSString* familyName;
}
@end
@implementation TomFamily
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError{NSString* str = *ioValue;if (str.length > 5) {return YES;} else {NSLog(@"输入字符数:%d,不大于5", str.length);return NO;}
}
@endint main(int argc, const char * argv[]) {@autoreleasepool {NSError* error;TomFamily* tomFamily = [[TomFamily alloc]init];NSString* value = @"Tom家族";if ([tomFamily validateValue:&value forKey:@"familyName" error:&error]) {[tomFamily setValue:value forKey:@"familyName"]; // 存值}NSLog(@"取出存入的数据: 家庭名称--%@",[tomFamily valueForKey:@"familyName"] // 取值并输出到控制台);}return 0;
}

输出结果

2020-07-11 12:48:24.830761+0800 kvcAndKvo[2489:3405389] 输入字符数:5,不大于5

三、mutableArrayValueForKey,用于取mutableArray类型的值

示例代码如下

@interface TomFamily : NSObject
{NSString* _familyName;NSMutableArray* _membersArr;
}
@end
@implementation TomFamily
-(id)init{if (self == [super init]){_membersArr = [[NSMutableArray alloc]initWithArray:@[@"father",@"mother",@"daughter"]];}return self;
}
@endint main(int argc, const char * argv[]) {@autoreleasepool {NSError* error;TomFamily* tomFamily = [[TomFamily alloc]init];NSLog(@"取出存入的数据: 家庭成员--%@",[tomFamily mutableArrayValueForKey:@"membersArr"] // 取值并输出到控制台);}return 0;
}

运行结果:

2020-07-11 17:31:26.427154+0800 kvcAndKvo[4997:3444350] 取出存入的数据: 家庭成员--(father,mother,daughter
)

四、 - (nullable id)valueForUndefinedKey:(NSString *)key,如果没有找到对应的key,则会调用这个方法

下面代码演示读取一个不存在的属性testName

@interface TomFamily : NSObject
{NSString* familyName;NSMutableArray* membersArr;
}
@end
@implementation TomFamily
- (id)valueForUndefinedKey:(NSString *)key{NSLog(@"你正在读取一个不存在的属性:%@", key);[super valueForUndefinedKey:key];return nil;
}
@endint main(int argc, const char * argv[]) {@autoreleasepool {NSError* error;TomFamily* tomFamily = [[TomFamily alloc]init];[tomFamily valueForKey:@"testName"];}return 0;
}

输出结果

2020-07-11 17:41:18.756170+0800 kvcAndKvo[5769:3455381] 你正在读取一个不存在的属性:testName
2020-07-11 17:41:18.761467+0800 kvcAndKvo[5769:3455381] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason:

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

//和上一个方法一样,只不过是设值,不赘述

- (void)setNilValueForKey:(NSString *)key;

//如果你在SetValue方法时面给Value传nil,则会调用这个方法,不赘述

六、 - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;

输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典;
以下是一个示例,把family中的familyName、address、tel三个属性取出,并返回一个字典对象。类似于lodash库中的pick函数:

@interface TomFamily : NSObject
{NSString* familyName;NSString* address;NSString* tel;
}
@end
@implementation TomFamily
@endint main(int argc, const char * argv[]) {@autoreleasepool {NSError* error;TomFamily* tomFamily = [[TomFamily alloc]init];[tomFamily setValuesForKeysWithDictionary:@{@"familyName":@"tom家族",@"address":@"北京",@"tel":@"15201923378"}];NSLog(@"批量取值:%@", [tomFamily dictionaryWithValuesForKeys:@[@"familyName",@"address",@"tel"]]);}return 0;
}

kvc实践一:核心方法和进阶相关推荐

  1. 【C++学习之路】第一章——C++核心方法总论

    1 C++核心方法总论 1.1 核心思想 通过实际项目来学习编程,更高效掌握编程规则,以及明白各种语法规则的实际应用. 实验思想:任何C++的参考资料都不可能覆盖你遇到的所有问题,这个时候,最好的办法 ...

  2. 2020-08-24绘制ROC   PR曲线 核心方法总结 ,计算AUC核心方法

    #1   绘制ROC AUC   PR曲线 #核心方法 roc_curve(y_test, preds)  #  preds为概率形式 #source code import matplotlib.p ...

  3. 【zepto学习笔记01】核心方法$()

    前言 我们移动端基本使用zepto了,而我也从一个小白变成稍微靠谱一点的前端了,最近居然经常要改到zepto源码 但是,我对zepto不太熟悉,其实前端水准还是不够,所以便私下偷偷学习下吧,别被发现了 ...

  4. form插件的核心方法--ajaxForm(),ajaxSubmit()

    方法1: <!DOCTYPE html> <meta charset="utf-8"> <html> <head> <titl ...

  5. Spring Cloud Gateway-ServerWebExchange核心方法与请求或者响应内容的修改

    Spring Cloud Gateway-ServerWebExchange核心方法与请求或者响应内容的修改 前提 本文编写的时候使用的Spring Cloud Gateway版本为当时最新的版本Gr ...

  6. 读jQuery之十二(删除事件核心方法)

    使用jQuery删除事件(或称解除事件绑定)有三个函数:unbind.die和undelegate.这三个方法都依赖于未公开的jQuery.event.remove(后续使用remove简写).此为删 ...

  7. Hibernate4之session核心方法

    在学习session的核心方法之前,我们先了解下hibernate中几种对象的状态: 暂时状态:这样的状态就好像咱们公司请的暂时员工一样,他在公司里没有相关的资料和id. 特点:在使用代理主键的情况下 ...

  8. Vuex中的核心方法

    Vuex中的核心方法 Vuex是一个专为Vue.js应用程序开发的状态管理模式,其采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.每一个Vuex应用的核心就是 ...

  9. Android Framework 电源子系统(05)核心方法updatePowerStateLocked分析-3 更新屏保  发送通知  更新wakelock

    该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统 本章关键点总结 & 说明: 本章节主要关注➕ updatePowerStateLocked 方法中 更新屏保 ...

最新文章

  1. Too many fragmentation in LMT?
  2. python中del和remove的区别_Python列表删除元素del、pop()和remove()的区别小结
  3. 华为鸿蒙系统如何升级,首批正式版没有荣耀,华为鸿蒙系统首批升级名单曝光:这些机主可坐等推送了...
  4. 由一条编译报错信息,引出两个Go编译的重要知识
  5. JAVA实现ATM源代码及感想
  6. 从Python调用C / C ++?
  7. linux 代码行数统计利器 ——cloc
  8. 全参考视频质量评价方法(PSNR,SSIM)以及相关数据库
  9. Excel制作二维码、条形码?你肯定没见过
  10. 如何把一张照片的像素提高_简单操作,让一张模糊的照片秒变清晰
  11. 测试质量报告-为了更好的下一个
  12. Win10桌面图标箭头去掉的方法总结
  13. 尼古拉斯·卡尔:IT发兵“云计算”
  14. win10系统设置选择电源键按钮功能设置步骤
  15. uniapp - app 获取短信内容
  16. 中联通首次确定3G上网资费 限流量包月150元
  17. STM32 USB AUDIO 基础篇①——通过STM32CubeMX生成USB Speaker音频播放Demo(史上最简单)
  18. Error creating bean with name 'transactionManager' defined i
  19. 数据库大作业代码展示2
  20. Linux环境下Kafka的下载配置和运行

热门文章

  1. java example使用_关于通用 Mapper Example 使用记录
  2. 多传感器融合定位 第四章 点云地图构建及基于点云地图定位
  3. SaaS前端规范架构
  4. Shell脚本中的流程控制,如if判断,case语句,for循环,while循环
  5. 甲骨文华育兴业|【大数据调查】80%的程序员年薪都在10万以上,三分之一的人年薪20万以上
  6. SATA接口的硬件基础知识
  7. K-Means 聚类算法C语言代码实现
  8. ThinkPHP上传图片并压缩为缩略图
  9. idea maven项目无法下载自定义的仓库完美解决办法
  10. c语言问题 输出字符类型及数量