您的位置:首页 > 其它

面向对象(键值编码(KVC)与键值监听(KVO))

2016-01-13 16:31 423 查看

面向对象(键值编码(KVC)与键值监听(KVO))

简单的KVC

最基本的KVC由NSKeyValueCoding协议提供支持,最基本的操作属性的两个方法如下

- setValue:属性值forKey:属性名 :为指定属性设置值。
- valueForKey:属性名:获取指定属性值


在KVC编程方式中,无论调用
setValue:forKey:
方法,还是调用
valueForKey:
方法,都是通过NSString对象来指定被操作属性的,其中forKey标签用于传入属性名。

对于”setValue:属性值 forKey@”name”;”代码,底层的执行机制如下。

1. 程序优先考虑调用"setName:属性值;"代码通过setter方法完成设置。
2. 如果该类没有setName:方法,那么KVC机制会搜索该类中名为_name的成员变量,无论该成员变量实在类接口部分定义,还是在
类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际就是_name成员变量赋值。
3. 如果该类既没有setName:方法,也没有定义_name成员变量,那么KVC机制会搜索该类中名为name的成员变量,无论该成员变量
是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条KVC代码底层实际上就是对name成员变量赋值。
4. 如果上面3步都没有找到,那么系统将会执行该对象的setValue:forUndefinedKey:方法(其实就是一个异常)


对于”valueforKey@”name”;”代码,底层的执行机制如下

1. 程序优先考虑调用"name;"代码来获取该getter方法的返回值。
2. 如果该类没有name方法,那么KVC机制会搜索该类中名为_name的成员变量,无论该成员变量实在类接口部分定义还是在类实现部
分定义,也无论调用哪个访问控制符修饰,这条KVC代码底层实际上就是返回_name成员变量的值。
3. 如果该类既没有name方法,也没有定义_name成员变量,那么KVC机制会搜索该类中名为name的成员变量,无论该成员变量实在类
接口部分定义还是在类实现部分定义,也无论调用哪个访问控制符修饰,这条KVC代码底层实际上就是返回name成员变量的值。
4. 如果上面3步都没有找到,那么系统将会执行该对象的valueForUndefinedKey:方法。(其实就是一个异常)


处理不存在的key

Objective-C并不存在绝对隐藏的方法,即使一个方法仅仅在类实现部分定义,根本不放在类接口部分定义,程序也依然可通过NSObject提供的performSelector:或performSelector:withObject:方法调用到Objective-C对象的方法。


key路径

在KVC协议中操作key路径的方法如下

- setValue:forKeyPath::根据key路径设置属性值。
- valueForKeyPath::根据key路径获取属性值。


实际上,通过KVC操作对象的性能比通过setter、getter方法操作的性能更差,使用KVC的优势在于编程更加灵活,更适合提炼一些通用性质的代码。由于KVC方式允许通过字符串形式来操作对象的属性,这个字符串既可是常量,也可是变量,因此具有极高的灵活性。

键值监听(KVO)

KVO机制由
NSKeyValueObserving
协议提供支持,
NSObject
遵守了该协议,所以
NSObject
的子类(所有的
Objective-C
类都是
NSObject
的子类)都可以使用该协议中的方法,该协议包含了如下常用方法用于注册监听器

- addObserver:forKeyPath:options:context::注册一个监听器用于监听指定的key路径。
- removeObserver:forKeyPath::为key路径删除指定的监听器。
- removeObserver:forKeyPath:context::为key路径删除指定的监听器。


例:
在.h文件中定义
@property (nonatomic ,weak ) FKItem * item;
- (void) showItemInfo;
在.m文件中定义
- (void) showItemInfo{
NSLog(@"item物品名为%@,物品价格为price:%d",self.item.name,self.item.price);
}
//自定义setItem:方法
- (void) setItem :(FKItem *)item{
self->_item = item;
//为item添加监听器,监听item的name属性的改变
[self.item addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
//为item添加监听器,监听item的name属性的改变
[self.item addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew context:nil];
}
//重写该方法,当被监听的数据模型组件发生改变时,就会调用监听器的该方法
- (void) observerValueForKeyPath:(NSString *)keyPath ofObject:(id) object change:(NSDictionary *)change context:(void *)context{
NSLog(@"--observerValueForKeyPath方法被调用--");
NSLog(@"被修改的keyPath为:%@",keyPath);
NSLog(@"被修改的对象为:%@",object);
NSLog(@"被修改的属性值为:%@",[change objectForKey:@"new"]);
NSLog(@"被修改的上下文为:%@",context);
}
- (void) dealloc{
//删除监听器
[self.item removeObserver:self forKeyPath:@"name"];
[self.item removeObserver:self forKeyPath:@"price"];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面向对象