您的位置:首页 > 移动开发 > IOS开发

面向对象3-键值编码(KVC)和键值监听(KVO)

2016-02-20 10:18 477 查看

键值编码(KVC)和键值监听(KVO)

KVC

@interface MyUser:NSObject
@property (nonatomic, copy) NSString* name;
@end
main()
{
@autoreleasepool
{
MyUser* user = [[MyUser allopc] init];
//用KVC方式为属性赋值
[user setValue:@"孙悟空" forKey:@"name"];
//用KVC方式获取属性值
NSLog(@"user's name is: %@", [user valueForKey:@"name"]);
}
}


KVC两种方法:

setValue:属性值 forKey:属性名 : 用于赋值

valueForKey:属性名 : 获取属性值

处理不存在的key

当key不存在时,会自动调用 setValue:forUndefinedKey: 和 valueForUndefinedKey: 由于这两个方法默认的方法体会引发 ‘NSUnknownKeyException’ 异常,并结束程序,一般情况下需要重写这两个方法。

- (void) setValue: (id) value forUndefinedKey: (id) key
{
NSLog(@"the key: (%@) being set does not exist!", key);
NSlog(@"the value being set is: %@", value);
}
- (void) valueForUndefinedKey: (id) key
{
NSLog(@"the key: (%@) being get does exist!", key);
}


处理nil值

非chat、NSString*类型的属性,不能赋予 nil ,可通过重写 NSObject 的 setNilValueForKey: 方法来将不合理的 nil 转化成合理的其他值

//省略代码:定义类接口和实现部分,分别呢含有 NSString* name 和 int price 属性,并为两个属性赋值 nil
//一下为重写 NSObject 的setNilValueForKey: 方法
- (void) setNilValueForKey: (id) key
{
//当尝试为 price 属性赋值 nil 时,执行以下语句
if([key isEqualToString:@"price"])
{
//将 price 赋值为0
price = 0;
}
else
{
//调回父类的 setNilValueForKey: 方法来赋值 nil
[super setNilValueForKey: key];
}
}


Key路径

KVC可对复合属性进行操作,所谓复合属性即:将已存在的类A作为本类B的属性,这样在本类B中亦可调用属性类A的属性(B.A.property)

#import <Foundation/Foundation.h>
#import "MyItem.h"
@interface MyItem: NSObject
@property NSString* name;
@property int price;
@end
@interface MyOrder: NSObject
//将 MyItem* 类对象作为属性
@property MyItem* item;
@end
//实现部分忽略,自行编写
int main(int argh, char * argv[])
{
@autoreleasepool
{
//创建MyOrder对象
MyOrder* order = [[MyOrder alloc] init];
//用KVC方式赋值
[order setValue:[[MyItem alloc] init] forKey:@"item"];
[order setValue:@"张三" forKey:@"item.name"];
[roder setValue:[NSNumber numberWithInt:25] forKey:@"item.price"];
//用KVC方式访问属性值
NSLog(@"name is: %@",[order calueForKey:@"item.name"]);
}
}


键值监听(KVO)

应用场景:数据模型组件中有数据发生修改,需视图组件实时更新

addObserver:forKeyPath:options:context: 注册监听器

removeObserver:forKeyPath: 删除监听器

removeObserver:foKea:contact: 删除监听器

//接口部分省略,自行编写
@implementation MyItemView
@snythesize item = _item;
- (void) setItem:(MyItem*) item    //自定义 setItem: 方法
{
self->_item = item;
//为item添加监听器,监听 name 属性, item为类属性,name为复合属性
[self.item addObserver:self forKeyPath:@"name"
options:NSKeyValueObservingOptionNew Context:nil];
}
//重写 observerValueForKeyPath: 方法,这样监听的数据模型发生改变时,就会回调监听器的该方法
- (void) observerValueForKeyPath:(NSString*) keyPath ofObject:(id) object chat:(NSDictionary*) change context:(void*)context
{
NSLog(@"--调用了 observerValueForKeyPath: 方法--");
NSLog(@"对象(%@)的属性(%@)被修改为 %@,被修改的上下文是 %@",object, keyPath, [hange objectForKey:@"new"], context);
}
- (void) dealloc
{
//删除监听器
[self.item removeObserver:self forKeyPath:@"name"];
}
@end


调用代码:

MyItem* item = [[MyItem alloc] init];
item.name = @"张三";    //由于视图组件没有创建
4000
对象,所以不会显示信息
MyItemView* itemView = [[MyItemView alloc] init];
[itemView showItemInfo];    //showItemInfo为输出信息方法,之前代码中省略掉了
item.name = @"李四";    //视图组件已创建对象,name属性被监听且值被更改,激发了监听器会输出结果


输出结果:

item name is: 张三
--调用了observerValueForKeyPath: 方法--
对象(<MyItem: 0x7faa02309780>)的属性(name)被修改为 李四,被修改的上下文是 (null)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面向对象 编码 IOS