利用KVC和associative特性在NSObject中存储键值(提示undefinedkey)

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"  forKeyPath:@"xx"];
NSLog(@"%@",[obj valueForKey:@"xx"]);

可以输出了吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值