面向对象3

来源:互联网 发布:linux环境高级编程 编辑:程序博客网 时间:2024/04/29 10:49

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

KVC

@interface MyUser:NSObject@property (nonatomic, copy) NSString* name;@endmain(){    @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 = @"张三"//由于视图组件没有创建对象,所以不会显示信息MyItemView* itemView = [[MyItemView alloc] init];[itemView showItemInfo];    //showItemInfo为输出信息方法,之前代码中省略掉了item.name = @"李四"//视图组件已创建对象,name属性被监听且值被更改,激发了监听器会输出结果

输出结果:

item name is: 张三--调用了observerValueForKeyPath: 方法--对象(<MyItem: 0x7faa02309780>)的属性(name)被修改为 李四,被修改的上下文是 (null)
0 0
原创粉丝点击