Objective-C面向对象(二) KVC及KVO学习
1.键值编码(KVC)与键值监听(KVO)
OC以字符串形式间接操作对象的属性,叫键值编码,Key Value Coding(KVC)
1.1简单的KVC
最简答的KVC由NSKeyValueCoding协议提供支持,最基本的操作属性的两个方法:
setValue:属性值 forKey:属性名
为指定属性协议设置值valueFoKey:属性名
获取指定属性的值
setValue:属性值 forKey:@"name"
的执行机制:
setName:属性值
(setter方法)->_name
成员变量->name
成员变量->setValue:forUndefinedKey:方法
为_name
或者name
成员属性赋值,不论属性是在类接口或者类实现部分,也不论用什么修饰符。setValue:forUndefinedKey:方法
会引发异常
valueforKey:@"name"
的执行机制
name;
(getter方法)->_name
成员变量->name
成员变量->valueforUndefinedKey:方法
(引发异常)
1.2 处理不存在的key
当使用KVC方式操作属性时,如果属性不存在,KVC将会自动调用setValue:forUndefinedKey:
和valueForUndefinedKey:方法
,系统默认实现的两个方法只是引发异常,没有进行任何特别的处理
在类实现部分重写 setValue:forUndefinedKey:
和valueForUndefinedKey:方法
,不需要在接口部分声明该方法
-(void) setValue:(id) value forUndefinedKey:(id)key
{
//value key
}
-(void) valueForUndefinedKey:(id)key
{
//key
}
1.3 处理nil值
当程序尝试为某个属性设置nil
值,如果该属性并不接受nil值,name程序将会自动执行该对象的setNilValueForKey:方法
。可重写这个方法。
-(void) setNilValueForKey:(id) key
{
if([key isEqualToString:@"price"])
{
price =0;
}
else
{
//回调父类的setNilValueForKey,执行默认行为
[super setNilValueForKey:key];
}
}
1.4 Key路径
KVC协议中操作Key路径的方法:
setValue:forKeyPath:
: 根据key路径设置属性值valueForKeyPath:
: 根据key路径获取属性值
1.5 键值监听(KVO)
KVO(Key Value Observing)机制NSKeyValueObserving协议提供支持,NSObject的子类都可以使用该协议中的方法。
addObserver:forKeyPath:options:context:
注册一个监听器监听指定的key路径removeObserver:forKeyPath:
为key路径删除指定的监听器removeObserver: forKeyPath: context:
删除指定的监听器
#import <Foundation/Foundation.h>
@interface FKItem:NSObject
@property (nonatomic) NSString* name;
@property int price;
@end
@implementation FKItem
@synthesize name;
@synthesize price;
@end
@interface FKItemView:NSObject
@property (nonatomic,weak) FKItem* item;
-(void) showItemInfo;
@end
@implementation FKItemView
@synthesize item = _item;
-(void) showItemInfo
{
NSLog(@"item物品名为%@,物品价格为:%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的price属性的改变
[self.item addObserver:self forKeyPath:@"price"
options:NSKeyValueObservingOptionNew
context:nil
];
}
//重写该方法,当被监听的数据模型发生改变时,就会回调监听器的该方法
-(void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object change:(NSDictionary*)change
context:(void *)context
{
NSLog(@"---observeValueForKeyPath方法被调用--");
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"];
}
@end
int main(int argc, char const *argv[])
{
@autoreleasepool{
FKItem* item = [[FKItem alloc] init];
item.name = @"测试KVO";
item.price =100;
FKItemView * itemview = [[FKItemView alloc] init];
itemview.item = item;
[itemview showItemInfo];
item.name = @"iOS";
item.price = 99;
}
}