KVC & KVO 入门

KVC:

简介:

全称 Key-Value Coding 。KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor(setter/getter)方法或是直接访问成员对象。KVC的key值必需小写,并且必须是对象内的属性或变量。可以访问一些没有暴露出来的变量。

使用:

[_bank setValue:@"I am Lee" forKey:@"name"];   // 设置值
[_bank valueForKey:@"name"];  //读取值

可以看出KVC的使用是非常简单的,但是只有KVC是不够的,还需要结合KVO来做。

 

KVO:

简介:

当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。主要使用KVO来实现对象属性和变量的监听。当有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。总的来说,就是不需要自己去定义消息的通知机制,只需关心对象的值的变化。

使用:

定义Bank.h文件

//
//  Bank.h
//  testDemo
//
//  Created by stardust on 15-1-15.
//  Copyright (c) 2015年 com. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Bank : NSObject
{
    NSString *name;
}
@property NSInteger money;
-(void)beRobbed;
@end

Bank.m文件:

//
//  Bank.m
//  testDemo
//
//  Created by stardust on 15-1-15.
//  Copyright (c) 2015年 com. All rights reserved.
//

#import "Bank.h"

@implementation Bank

//@synthesize money;

-(void)beRobbed{
    self.money = self.money - 100;
}
@end

APerson.h文件:

//
//  APeron.h
//  testDemo
//
//  Created by stardust on 15-1-15.
//  Copyright (c) 2015年 com. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface APeron : NSObject

@end

APerson.m文件:

//
//  APeron.m
//  testDemo
//
//  Created by stardust on 15-1-15.
//  Copyright (c) 2015年 com. All rights reserved.
//

#import "APeron.h"


@implementation APeron

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"KVC old name is %@ , new name is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]);
    }
    else if([keyPath isEqualToString:@"money"]){
        NSLog(@"KVC old money is %@ , new money is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]);
    }
    else{
        NSLog(@"KVC old value is %@ , new value is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]);  
    }
}

@end

主文件KVOController.m:

//
//  KVOViewController.m
//  testDemo
//
//  Created by stardust on 15-1-15.
//  Copyright (c) 2015年 com. All rights reserved.
//

#import "KVOViewController.h"
#import "Bank.h"
#import "APeron.h"


@interface KVOViewController ()
@property APeron *aperson;
@property Bank *bank;
@end

@implementation KVOViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    _aperson = [[APeron alloc]init];
    _bank = [[Bank alloc]init];
    
    [_bank addObserver:_aperson forKeyPath:@"name" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:@"hello"];
    [_bank addObserver:_aperson forKeyPath:@"money" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"hello2"];
    [_bank addObserver:_aperson forKeyPath:@"jack" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:@"hello3"];
    
    [_bank setValue:@"I am Lee" forKey:@"name"];
    _bank.money = 101;
    [_bank beRobbed];
    
    NSLog(@"... %@",[_bank valueForKey:@"name"]);
    
    //[_bank setValue:@"Tim Jack" forKey:@"jack"];  // 此句报错
    
    

    // 一定要移除kvo,不然会有可能报错


    [_bank removeObserver:_aperson forKeyPath:@"name"];


    [_bank removeObserver:_aperson forKeyPath:@"money"];


    [_bank removeObserver:_aperson forKeyPath:@"jack"];


}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

显示结果:

2015-01-15 19:36:52.256 testDemo[3442:634253] KVC old name is <null> , new name is I am Lee
2015-01-15 19:36:52.257 testDemo[3442:634253] KVC old money is 0 , new money is 101
2015-01-15 19:36:52.257 testDemo[3442:634253] KVC old money is 101 , new money is 1
2015-01-15 19:36:52.258 testDemo[3442:634253] ... I am Lee

 

通过以上可以看出,设置aperson来监听Bank对象的变化,监听变化的处理放在APerson中,只要Bank对象中被监听的值发生变化,无论是直接设置改变,还是通过KVC,都能监听得到并执行相关监听的逻辑。但是,对于不存在的值,例如主文件代码中注释了的这句:” [_bank setValue:@"Tim Jack" forKey:@"jack"];“,即使可以添加不存在值的监听,但是调用相应的KVC时,会crash,这可能跟KVC的机制有关。

 

参考:

1

 

posted @ 2015-01-15 20:01  月之星狼  阅读(290)  评论(0编辑  收藏  举报