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;
	}
}
posted @ 2015-04-20 23:06  逍遥锅锅  阅读(272)  评论(0编辑  收藏  举报