基本概念
KVO(键值观察)是使用获取其他对象的特定属性变化的通知机制。控制器层的绑定技术就是严重依赖键值观察获得模型层和控制器层的变化通知的。对于不依赖控制器层类的应用程序,键值观察提供了一种简化的方法来实现检查器并更新用户界面值。
与NSNotification不同,KVO中并没有所谓的中心对象来为所有观察者提供变化通知。取而代之的,当有变化发生时,通知被直接发送至处于观察状态对象。NSObject提供这种基础的键KVO实现方法,你几乎不用重写这些方法。可以观察任何对象属性,包括基本数据类型属性,对一或是对多关系。对多关系的观察者将会被告知发生变化的类型,也就是任意发生变化的对象。
键值观察为所有对象提供自动观察兼容性,你可以通过禁用通过并实现手动通知来筛选通知。
创建一个观察者
[_child addObserver:self forKeyPath:@"cleanValue" options:nil context:nil];
这里的_child指的是需要观察的对象;self指的是响应事件的人,也就是观察者;forkeypath指的是需要观察的属性;options:传递给接收者的值的类型,旧的还是新的;context指的是,额,现在的我还不清楚..
这个代码的作用是消息至被观察对象,用以传送观察者和需要观察的属性的关键路径,以便与其注册。选项参数指定了发送变更通知时提供给观察者的信息。使用NSKeyValueObservingOptionsOld选择可以将初始对象值以变更字典中的一个项
的形式提供给观察者。指定NSKeyValueObservingOptionsNew选择可以将新的值以一个项的形式添加至变更字典。你可以使用逐位“|”这两个常量来指定接受上述两种类型的值。
下面举一个例子
Nanny.h文件
#import <Foundation/Foundation.h>
#import "Child.h"
@interface Nanny : NSObject
@property (nonatomic,assign) Child *child;
- (instancetype)initWithChild:(Child *)child;
@end
Nanny.m文件
#import "Nanny.h"
@implementation Nanny
- (instancetype)initWithChild:(Child *)child {
self = [super init];
if (self) {
_child = child;
[_child addObserver:self forKeyPath:@"cleanValue" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change context:(void *)context {
/*object:是观察的对象,在这里指child,可以用类型强转
*change:是一个字典,里面包含了观察属性的值,新的,旧的多个观察者,用if判断关键属性是否相等执行相应操作
*/
if ([keyPath isEqualToString:@"cleanValue"]) {
NSNumber *valueObj = change[@"new"];
NSInteger value = [valueObj integerValue];
if (value < 90) {
NSLog(@"保姆给小孩洗澡");
// 通过objcet取得小孩对象
Child *ch = (Child *)object;
// 重新设置小孩的值
ch.cleanValue = 100;
}
}
}
- (void)dealloc {
[_child removeObserver:self forKeyPath:@"cleanValue"];
}
观察者要手动释放!!!在dealloc方法里调用removeObserver方法.
Child.h文件
#import <Foundation/Foundation.h>
@interface Child : NSObject
@property (nonatomic,assign) NSInteger cleanValue;
@end
Child.m文件
#import "Child.h"
@implementation Child
- (instancetype)init
{
self = [super init];
if (self) {
self.cleanValue = 100;
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(timeAc:)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)timeAc:(NSTimer *)timer {
// 观察者,可以观察值的变化,但是系统设定如果观察者要响应值的变化,必须通过设置器方法修改值
// _cleanValue —;
self.cleanValue = _cleanValue - 2;
NSLog(@"cleanValue:%ld", _cleanValue);
}
@end
main.m函数
#import <Foundation/Foundation.h>
#import "Child.h"
#import "Nanny.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Child *c1 = [[Child alloc] init];
Nanny *n1 = [[Nanny alloc] initWithChild:c1];
[[NSRunLoop currentRunLoop] run];
}
return 0;
}
新手来着,如有错误忘告知,共同进步~