前人已经说的很清楚了!我也没必要在重复了!我也没人家总结的好!
下面介绍来自
http://www.cppblog.com/kesalin/archive/2012/11/17/kvo.html 总结的很全面 值得研究
一,前言
Objective-C 中的键(key)-值(value)观察(KVO)并不是什么新鲜事物,它来源于设计模式中的观察者模式,其基本思想就是:
一个目标对象管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。这个主动通知通常是通过调用各观察者对象所提供的接口方法来实现的。观察者模式较完美地将目标对象与观察者对象解耦。
在 Objective-C 中有两种使用键值观察的方式:手动或自动,此外还支持注册依赖键(即一个键依赖于其他键,其他键的变化也会作用到该键)。下面将一一讲述这些,并会深入 Objective-C 内部一窥键值观察是如何实现的。
二,运用键值观察
1,注册与解除注册
如果我们已经有了包含可供键值观察属性的类,那么就可以通过在该类的对象(被观察对象)上调用名为 NSKeyValueObserverRegistration 的 category 方法将观察者对象与被观察者对象注册与解除注册:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
这两个方法的定义在 Foundation/NSKeyValueObserving.h 中,NSObject,NSArray,NSSet均实现了以上方法,因此我们不仅可以观察普通对象,还可以观察数组或结合类对象。在该头文件中,我们还可以看到 NSObject 还实现了 NSKeyValueObserverNotification 的 category 方法(更多类似方法,请查看该头文件):
- (void)willChangeValueForKey:(NSString *)key; - (void)didChangeValueForKey:(NSString *)key;
这两个方法在手动实现键值观察时会用到,暂且不提。
值得注意的是:不要忘记解除注册,否则会导致资源泄露。
2,设置属性
将观察者与被观察者注册好之后,就可以对观察者对象的属性进行操作,这些变更操作就会被通知给观察者对象。注意,只有遵循 KVO 方式来设置属性,观察者对象才会获取通知,也就是说遵循使用属性的 setter 方法,或通过 key-path 来设置:
[target setAge:30]; [target setValue:[NSNumber numberWithInt:30] forKey:@"age"];
3,处理变更通知
观察者需要实现名为 NSKeyValueObserving 的 category 方法来处理收到的变更通知:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
在这里,change 这个字典保存了变更信息,具体是哪些信息取决于注册时的 NSKeyValueObservingOptions。
我先创建了一个 dogName 的函数作为被观察的对象
dogName.h 文件 邪恶的下划线/
#import <Foundation/Foundation.h>
@interface dogName :NSObject
{
NSString *dongNameString;
}
@property (strong,nonatomic)NSString *dongNameString;
@end
dogName.m 文件 邪恶的下划线/
#import "dogName.h"
@implementation dogName
@synthesize dongNameString;
-(id)init
{
if (self = [superinit])
{
//初始化了一条狗 这条狗看家
dongNameString = [self setDogName:@"大黄"];
//6秒后 名叫小花的狗来接替大黄这条狗看家
[NSTimerscheduledTimerWithTimeInterval:6target:selfselector:@selector(changeName)userInfo:nilrepeats:NO];
}
returnself;
}
-(void)changeName
{
[selfsetValue:[self setDogName:@"大黄走了小花来了"] forKey:@"dongNameString"];
}
-(NSString *)setDogName:(NSString *)name
{
return name;
}
//自动通知 大黄走了小花来了一定要告诉主人来 谁在看家
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString*)key
{
// 对于名为dongNameString的变更通知,使用自动通知
if ([key isEqualToString:@"dongNameString"])
{
returnYES;
}
// 确保调用了父类的automaticallyNotfiesObserversForKey方法
return [superautomaticallyNotifiesObserversForKey:key];
}
#import <UIKit/UIKit.h>
#import "dogName.h"
@interface ViewController :UIViewController
{
dogName *dogname;
}
@property (weak,nonatomic)IBOutlet UILabel *dogNameLable; //在视图上显示哪个狗在看家
@end
/// 在 ViewController.m 里 //
#import "ViewController.h"
#import "dogName.h"
@interfaceViewController ()
@end
@implementation ViewController
@synthesize dogNameLable;
- (void)viewDidLoad
{
[superviewDidLoad];
dogname = [[dogName alloc]init];
//注册观察者 狗主人
[dogname addObserver:self
forKeyPath:@"dongNameString"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
//观察者对象的属性进行操作 看看哪条狗在看家
dogNameLable.text = [dogname valueForKey:@"dongNameString"];
}
// 处理变更通知 狗主人的眼睛 能观察到是否有其他的狗来接班
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"%@",keyPath);
if ([keyPath isEqual:@"dongNameString"])
{
dogNameLable.text=[change objectForKey:NSKeyValueChangeNewKey];
}else
{
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
//搬家了就要 删除观察者
-(void)dealloc
{
[dogname removeObserver:self forKeyPath:@"dongNameString"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
遛狗的demo: http://download.csdn.net/detail/lengshengren/6506879