Objective-C KVO的简单概述和示例

KVO(Key Value Observing)是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数 据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类 似Notification,但是notification是需要一个发送notification的对象,一般是 notificationCenter,来通知观察者。而kvo是直接通知到观察对象。)

when use KVO,it usually follows below:

1 注册:

- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)

2 实现变化方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void*)context

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

是不是很简单?kvo的逻辑非常清晰,实现步骤简单。

说了这么多,大家都要跃跃欲试了吧。可是,在此之前,我们还需要了解KVC机制。看看这篇文章的使用-Object-C KVC的简单概述和示例


演示一个实例看看:

创建两个类Child和Nurse

Child.h

//
//  Child.h
//  KVODemo
//
//  Created by Durban on 13-12-19.
//  Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Child : NSObject

@property (nonatomic,assign) NSInteger happyVal;

@end

Child.m

//
//  Child.m
//  KVODemo
//
//  Created by Durban on 13-12-19.
//  Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "Child.h"

@implementation Child

-(id) init
{
    self = [super init];
    if(self != nil)
    {
        _happyVal = 100;
        [NSTimer scheduledTimerWithTimeInterval:1
                                         target:self
                                       selector:@selector(timerAction:)
                                       userInfo:nil
                                        repeats:YES];
    }
    
    return self;
}

-(void) timerAction:(NSTimer *)timer
{
    self.happyVal--;//必须使用点语法
    //第二种语法
//    _happyVal--;
//    [self setValue:[NSNumber numberWithInteger:_happyVal] forKey:@"happyVal"];
}

@end

Nurse.h

//
//  Nurse.h
//  KVODemo
//
//  Created by Durban on 13-12-19.
//  Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>

@class Child;
@interface Nurse : NSObject

@property (nonatomic, retain) Child *child;
-(id) initWithChild:(Child *)child;

@end

Nurse.m

//
//  Nurse.m
//  KVODemo
//
//  Created by Durban on 13-12-19.
//  Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "Nurse.h"
#import "Child.h"

@implementation Nurse
@synthesize child = _child;

-(id) initWithChild:(Child *)child
{
    self = [super init];
    if(self != nil)
    {
        _child = child;
        [_child addObserver:self
                 forKeyPath:@"happyVal"
                    options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                    context:@"xx"];
    }
    
    return self;
}

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"change = %@",change);
}

@end

测试实现过程如下:

//
//  main.m
//  KVODemo
//
//  Created by Durban on 13-12-19.
//  Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Child.h"
#import "Nurse.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Child *child = [[Child alloc] init];
        Nurse *nurse = [[Nurse alloc] initWithChild:child];
        [[NSRunLoop currentRunLoop] run];
        // insert code here...
        NSLog(@"Hello, World!");
        
    }
    return 0;
}

得到的结果是:

2013-12-19 10:58:58.364 KVODemo[36662:303] change = {
    kind = 1;
    new = 99;
    old = 100;
}
2013-12-19 10:58:59.359 KVODemo[36662:303] change = {
    kind = 1;
    new = 98;
    old = 99;
}
2013-12-19 10:59:00.359 KVODemo[36662:303] change = {
    kind = 1;
    new = 97;
    old = 98;
}
2013-12-19 10:59:01.358 KVODemo[36662:303] change = {
    kind = 1;
    new = 96;
    old = 97;
}
Program ended with exit code: 9

如果得到如上的结果,说明使用是正确的


参考文章:

http://blog.csdn.net/weiwangchao_/article/details/7454968