KVC 

 一直没仔细看过KVC的用法,想当然的认为可以在NSObject对象中存入任意键值对,结果使用时碰到问题了。

  一个简单的位移动画:

CAKeyframeAnimation *keyPosi=[CAKeyframeAnimation animationWithKeyPath:@"position"];
keyPosi.path=path.CGPath;
keyPosi.delegate=self;
[label.layer addAnimation:keyPosi forKey:@"x"];

  我想要在动画结束后把UILabel从屏幕上移除,于是加上动画结束后的回调:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{}

  然而看上去从回调方法的参数中似乎无法得到UILabel对象(也许提供的有api可以获得UIlabel,希望各位看官不吝赐教),如果只是为了在这里得到UILabel对象而去设置一个全局变量指针指向它感觉没必要,这时候我想起了KVC,于是在创建动画的时候加上一句:

[keyPosi setValue:label forKey:@"xx"];

  这样在动画结束的回调方法中可以通过anim参数获得UILabel对象了:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{

if (flag) {

UIView *vie=[anim valueForKey:@"xx"];

[vie removeFromSuperview];

}

}

  效果已经实现,然而KVC是这样使用的吗?再看一个例子:

NSObject *obj = [[NSObject alloc] init];
[obj setValue:@"asd"  forKey:@"xx"];

  运行报错:

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

  原来setValue:forKey、setValue:forKeyPath的key(Path)参数不是随便写的,必须是类中定义的成员变量名(或者实例方法),这篇文章写的很清楚:http://www.cnblogs.com/jay-dong/archive/2012/12/13/2815778.html。话说回来,为啥前面CAKeyframeAnimation使用的setValue:forKey的key可以成功设置?类里肯定没有xx这个成员变量。继续查资料发现有个方法setValue:forUndefinedKey:,

setValue:forUndefinedKey:
Invoked by setValue:forKey: when it finds no property for a given key.- (void)setValue:(id)value forUndefinedKey:(NSString *)key
Discussion
Subclasses can override this method to handle the request in some other way. The default implementation raises an NSUndefinedKeyException.

  当setValue方法的key参数在类中找不到对应成员时,会调用这个方法,重写它可以阻止抛出NSUndefinedKeyException异常。

  这样看来,CAKeyFrameAnimation类(或者它的父类)应该是重写了setValue:forUndefinedKey:,然而方法里是怎样处理从而使得valueForKey可以正确取到值呢?

associative

  objective-c的扩展机制有两个特性:category和associative。category扩展类别,associative扩展属性。使用associative需要导入<objc/runtime.h>头文件。

  利用category扩展NSObject类别,利用associative和setValue:forUndefinedKey:让NSObject能够存入任意键值对。

#import <objc/runtime.h>
@interface NSObject (KVC)
- (id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
@end@implementation NSObject(KVC)
- (id)valueForUndefinedKey:(NSString *)key{return objc_getAssociatedObject(self, key);
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{if ([value isKindOfClass:[NSString class]]) {objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_COPY_NONATOMIC);}else{objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}}
@end

  现在再试下:

NSObject *obj = [[NSObject alloc] init];
[obj setValue:@"asd"  forKey:@"xx"];
NSLog(@"%@",[obj valueForKey:@"xx"]);

  可以输出了吧。

更正!

   对各位说声抱歉,之前犯了一个想当然的错误,setValue:forUndefinedKey:和valueForUndefinedKey:两个方法中的key不能直接传给setAssociatedObject和getAssociatedObject方法,如下所示的做法是错误的:

NSString *a=[NSString stringWithFormat:@"hello"];
NSString *b=[NSString stringWithFormat:@"hello"];
[self setValue:@"cannotfind" forKey:a];
NSString *result=[self valueForKey:b];
NSLog(@"%@",result);

  这里result是空,因为a、b是两个不同指针,setAssociatedObject和getAssociatedObject使用了不同的key。正确的做法是定义全局静态变量作为key:

static NSString *kHello=@"hello";

[self setValue:@"canfind" forKey:kHello];
NSString *result=[self valueForKey:kHello];
NSLog(@"%@",result);

  或者这样:

static char kHello;- (id)valueForUndefinedKey:(NSString *)key{const void *newkey=nil;if ([key isEqualToString:@"hello"]) {newkey=&kHello;}else{NSAssert(false, @"undefined key");}return objc_getAssociatedObject(self, newkey);
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{const void *newkey=nil;if ([key isEqualToString:@"hello"]) {newkey=&kHello;}else{NSAssert(false, @"undefined key");}if ([value isKindOfClass:[NSString class]]) {objc_setAssociatedObject(self, newkey, value, OBJC_ASSOCIATION_COPY_NONATOMIC);}else{objc_setAssociatedObject(self, newkey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}}

转载于:https://www.cnblogs.com/powerauras/p/3323497.html

(bug更正)利用KVC和associative特性在NSObject中存储键值相关推荐

  1. 利用SQL Server 2005特性删除表中重复数据

    http://www.cnblogs.com/haosola/archive/2010/02/04/1663150.html 转载于:https://www.cnblogs.com/modernsky ...

  2. 数组中的键值对去重_javascript利用对象键值对中键的唯一性实现数组去重

    /p> "http://www.w3.org/TR/html4/loose.dtd"> var arr = [1,2,3,2,3,4,5,6,7,8,9,8,5]; / ...

  3. vba 提取 json某个值_利用VBA字典,提取两列数据的重复值

    大家好,今日我们继续讲解VBA数组与字典解决方案,今日讲解第52讲:利用字典,提取两列数据重复值.有人讲:字典是VBA中最为精华的部分,持这种观点的人肯定有自己的道理,确实,利用字典可以给我的代码带来 ...

  4. Sky Computing:利用空间异构分布式计算特性加速联邦学习

    在AI浪潮中,无论是企业还是国家,对算力的需求都日益高涨.近期启动的"东数西算"项目,更是从宏观层面大力打造AI基础设施.但位于不同地理位置的计算机之间通信延迟较高,如何统筹兼顾. ...

  5. 论文阅读:基于区块链的一个车联网轻量级安全V2V通信特点:利用无线网络传输在V2V通信中的信道特性,生成特殊的LF(链路指纹)用于标识每个信道,区块链技术用于生成区块

    论文阅读:基于区块链的一个车联网轻量级安全V2V通信特点:利用无线网络传输在V2V通信中的信道特性,生成特殊的LF(链路指纹)用于标识每个信道,区块链技术用于生成区块. 系统模型: 汽车使用MICAz ...

  6. 利用sEMG能量高斯分布特性提取动作信号的方法

    肌电论文 前言:下一步要学习自己的研究方向,关于肌电信息和脑电信息,然对此领域涉及太浅,遂从论文开始着手! 利用sEMG能量高斯分布特性提取动作信号的方法 摘要:对于采集到的连续动作肌电信号,首先要进 ...

  7. 海岛大亨6图像处理错误_《海岛大亨6》bug有效利用方法 一般人我不告诉他

    这个游戏大家都玩过,但是很多玩家不知道<海岛大亨6>中bug怎么利用,其实小编一开始也不知道这个.今天牛游网小编就给大家分享一下<海岛大亨6>bug有效利用方法分享,希望大家能 ...

  8. C++新特性探究(13.6):右值引用再探究

    相关博文: C++新特性探究(十三):右值引用(r-value ref)&&探究 C++新特性探究(十六):move constructor移动构造 C++新特性探究(13.5):右值 ...

  9. 从QQ音乐开发,探讨如何利用腾讯云SDK在直播中加入视频动画

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由 腾讯游戏云发表于 云+社区专栏 看着精彩的德甲赛事,突然裁判一声口哨,球赛断掉了,屏幕开始自动播放"吃麦趣鸡盒,看德甲比赛 ...

  10. 利用python获取指定url在ATS中缓存对象的信息

    业务需求 给定url,如何查询指定的ATS中是否有该url的缓存对象信息?如果缓存了的话,希望提供该缓存对象的大小,缓存时间,缓存文件名,缓存份数(document alternative)等等信息 ...

最新文章

  1. 有了AD,还需要WINS吗?
  2. HBase java 开发
  3. C语言基础-简单程序分析
  4. 删除数据文件—启动不了数据库--恢复数据库—启动数据库
  5. Native snappy library not available: this version of libhadoop was built without snappy support
  6. 用Ghost进行备份还原
  7. jsp与php学哪个2015年,PHP和jsp哪个好学呢?
  8. 错误3:系统找不到指定的路径
  9. 20144303 《Java程序设计》第一周学习总结
  10. QTP的那些事--打开脚本文件弹出“unexpected file format”错误
  11. 手机号码检测开通微信工具如何进行选择
  12. abaqus2018安装教程win10_win10环境下如何安装abaqus6.12?windows10环境安装abaqus6.12的方法...
  13. 守望先锋:源氏跑酷之球图制作分享
  14. 【NOI OJ】1818 红与黑
  15. sublime text3 unicode 中文转换
  16. 1-乙基-3-甲基咪唑醋酸盐([EMIM][Ac]);甲基三辛基醋酸铵[N(1,8,8,8)][Ac]齐岳离子液体
  17. Android封装sdk页面为h5,Android/H5混合 SDK 集成文档
  18. vue中使用svg画路径图
  19. 网页播放的本地视频代码
  20. 匠心铸梦 敏涵控股集团打造民族领军品牌

热门文章

  1. 百问网7天物联网智能家居 学习心得 打卡第三天
  2. Swagger文档转Word 文档
  3. python 聚合_Python数据聚合
  4. 内外网数据交换方式有哪些?
  5. 渗透测试之信息收集漏洞库篇
  6. MATLAB——更换主题颜色
  7. Node 的 cross-env 模块
  8. Essential Qt 第二十一章 本地目录
  9. 安卓ps2模拟器_安卓PSP模拟器评测:火影忍者究极冲击
  10. java excel 密码_用java实现对EXCEL加打开密码的方法?