在技术论坛中看到一则很有意思的KVC案例:,第一反应是崩溃,因为OC是类型敏感的。可是自己实现并打印后的结果出于意料,没有崩溃且赋值成功。所以有了深入了解KVC的内部实现的想法!,key–value-coding:键值编码,一种可以通过键名间接访问和赋值对象属性的机制
KVC是通过NSObject、NSArray、NSDictionary等的类别来实现的
主要方法包括一下几个:,那么上面的案例中的- (void)setValue:(nullable id)value forKey:(NSString *)key;是怎样的执行过程呢?借助反汇编工具获得Foundation.framework部分源码(为了解决和系统API冲突问题增加前缀_d,NS替换为DS),以此分析KVC执行过程。(流程中的边界判断等已经忽略,如想了解可以参考源码,本文只探究主流程。),查找顺序如下:,则查找顺序如下:_,_is,,is
查找不到则调用valueForUndefinedKey并抛出异常,,基本的访问器方法、变量的查找和异常处理已经清楚的知道了。那么上面的例子是如何出现的呢?明明传入的是字符串,最后赋值的时候转变为访问器方法所对应的类型?继续刨根问底!,DSKeyValueSetter对象已经生成,即确定了发送消息的对象object、访问器方法名SEL、访问器函数指针IMP、以及使用KVC时传入的Key和Value。下面进入方法调用阶段:_DSSetUsingKeyValueSetter(self,setter, value);,,IMP指针为_DSSetIntValueForKeyWithMethod其定义如下:之所以有文章开头提到的效果就是这里起了作用,在IMP调用的时候做了[value valueGetSelectorName],将对应的NSNumber转换为简单数据类型。这里是intValue。,起始问题完美解决!执行流程如下:,,单步调试后可以看到具体的IMP类型,,定义如下:,取值调用如下:,,NSNunber:,,NSValue,,修改数组中对象的属性[array valueForKeyPath:@”uppercaseString”]利用KVC可以批量修改属性的成员变量值,求和,平均数,最大值,最小值NSNumbersum= [array valueForKeyPath:@”@sum.self”];NSNumberavg= [array valueForKeyPath:@”@avg.self”];NSNumbermax= [array valueForKeyPath:@”@max.self”];NSNumbermin= [array valueForKeyPath:@”@min.self”];,经过上面的分析可以明白KVC的真正执行流程。下面结合日常工程中的实际应用来优雅的处理数据筛选问题。使用KVC处理可以减少大量for的使用并增加代码可读性和健壮性。
如图所示:,,项目中的细节如下:修改拒收数量时更新总妥投数和总拒收数、勾选明细更新总妥投数和总拒收数、全选、清空、反选。如果用通常的做法是每次操作都要循环去计算总数和记录选择状态。下面是采用KVC的实现过程。
模型涉及:,1)更新总数,2)全选
[self.orderDetailModel.deliveryGoodsDetailList setValue:@(YES) forKeyPath:@”selected”];,3)清空
[self.orderDetailModel.deliveryGoodsDetailList setValue:@(NO) forKeyPath:@”selected”];,4)反选,KVC在处理简单数据类型时会经过数据封装和拆装并转换为对应的数据类型。通过KVC的特性我们可以在日常使用中更加优雅的对数据进行筛选和处理。优点如下:可阅读性更高,健壮性更好。
© 版权声明
文章版权归作者所有,未经允许请勿转载。