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

本文介绍了KVC和KVO在对象属性操作中的使用方法,包括赋值、获取属性值及处理不存在的key、nil值的情况,并通过实例展示了如何在复合属性上进行操作。此外,文章还详细阐述了KVO的应用场景,通过实例演示了如何为数据模型组件添加实时更新视图组件的监听器。

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

输出结果:

item name is: 张三
--调用了observerValueForKeyPath: 方法--
对象(<MyItem: 0x7faa02309780>)的属性(name)被修改为 李四,被修改的上下文是 (null)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值