KVO:key value observer 键值对的观察者
功能:给对象属性添加观察者,用来时时监测对象属性值的改变,一旦属性值发生了改变,观察者就做出相应的反应,提醒用户。在应用中,针对MVC模式,数据库中的数据模型发生变化时,引起视图界面的改变,此时使用KVO进行数据的监测是一个不错的机制。
步骤:
1.添加观察者
2.接收变动通知
3.删除观察者
详细介绍:
键值通知枚举
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
NSKeyValueObservingOptionNew = 0x01,
NSKeyValueObservingOptionOld = 0x02,
NSKeyValueObservingOptionInitial = 0x04,
NSKeyValueObservingOptionPrior= 0x08
};
内置的通知键
FOUNDATION_EXPORT NSString *const NSKeyValueChangeKindKey;
FOUNDATION_EXPORT NSString *const NSKeyValueChangeNewKey;
FOUNDATION_EXPORT NSString *const NSKeyValueChangeOldKey;
FOUNDATION_EXPORT NSString *const NSKeyValueChangeIndexesKey;
FOUNDATION_EXPORT NSString *const NSKeyValueChangeNotificationIsPriorKey ;
@interface NSObject(NSKeyValueObserving)
//接受被观察者发出变动后的通知
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
@end
@interface NSObject(NSKeyValueObserverRegistration)
//通过键给对应的属性添加观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//删除观察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
@end
@interface NSArray(NSKeyValueObserverRegistration)————— 数组的KVO机制
NSIndexSet 是个无符号整数集合。集合中的元素不可变的、不可重复。常被用来当作索引使用
//通过键给对应的数组中指定索引的属性添加观察者
- (void)addObserver:(NSObject *)observer toObjectsAtIndexes:(NSIndexSet *)indexes forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//删除观察者
- (void)removeObserver:(NSObject *)observer fromObjectsAtIndexes:(NSIndexSet *)indexes forKeyPath:(NSString *)keyPath context:(void *)context;
- (void)removeObserver:(NSObject *)observer fromObjectsAtIndexes:(NSIndexSet *)indexes forKeyPath:(NSString *)keyPath;
//通过键给对应的数组添加观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//删除观察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
@end
@interface NSSet(NSKeyValueObserverRegistration)—————集合的KVO机制
//通过键给对应的set集合添加观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//删除观察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
@end
@interface NSObject(NSKeyValueObserverNotification)————观察者通知
//对于单个对象
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;
//对于array数组
- (void)willChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key;
- (void)didChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key;
//对于set集合
- (void)willChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind usingObjects:(NSSet *)objects;
- (void)didChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind usingObjects:(NSSet *)objects;
@end
具体演示实例如下:
要求:将人设置为股票的观察者,一旦股票价格发生改变,就立刻发送即时信息。
准备工作:
在控制器视图中添加一个按钮控件并关联事件IBAction,用来点击时改变股票的价格,需要的文件相关截图为:
以下就是代码的实现了:
Person人类:
Person.h
//声明属性
#import <Foundation/Foundation.h> @interface Person : NSObject { NSString *_name; } @end
Perosn.m
//接受观察者发来的即时信息
#import "Person.h" @implementation Person //接收被观察者发生变动后的通知 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"keyPath:%@,object:%@,change:%@",keyPath,object,change); } @end
Stock股票类:
Stock.h
//声明属性
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface Stock : NSObject { NSString *_name; CGFloat _price; } @end
ViewController控制器类
//声明属性
#import "ViewController.h" #import "Person.h" #import "Stock.h" @interface ViewController () @property (strong,nonatomic)Person *person; @property (strong,nonatomic)Stock *stock; @end @implementation ViewController
//按钮事件,点击时改变股票的价格
//按钮事件,改变股票价格 - (IBAction)buttonClicked:(UIButton *)sender { CGFloat price = [[self.stock valueForKey:@"_price"] floatValue]; [self.stock setValue:@(price+0.1) forKey:@"_price"]; }
//创建对象并添加观察者
- (void)viewDidLoad { [super viewDidLoad]; //创建人和股票对象 self.person = [[Person alloc]init]; [self.person setValue:@"Tom" forKey:@"_name"]; self.stock = [[Stock alloc]init]; [self.stock setValue:@"sh0001" forKey:@"_name"]; [self.stock setValue:@12.5 forKey:@"_price"]; //添加观察者(观察股票的变动) [self.stock addObserver:self.person forKeyPath:@"_price" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; }
//程序结束,删除观察者
-(void)dealloc { //删除观察者 [self.stock removeObserver:self.person forKeyPath:@"_price"]; }
演示结果如下:
点击第一次,输出股票价格更新即时信息
2015-10-14 22:02:56.298 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.6"; old = "12.5"; }
点击第二次,输出股票价格更新即时信息
2015-10-14 22:02:56.298 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.6"; old = "12.5"; } 2015-10-14 22:03:44.913 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.70000038146973"; old = "12.6"; }
点击第三次,输出股票价格更新即时信息
2015-10-14 22:02:56.298 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.6"; old = "12.5"; } 2015-10-14 22:03:44.913 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.70000038146973"; old = "12.6"; } 2015-10-14 22:04:09.448 02-KVO[5612:319932] keyPath:_price,object:<Stock: 0x7f9679482c40>,change:{ kind = 1; new = "12.80000076293945"; old = "12.70000038146973"; }