KVC、KVO的用法

KVC、KVO的用法
    一、KVC
      1.概念
KVC是Key Value Coding的简称,它是一种可以直接通过字符串的名字(Key)来访问类属性的机制。使用该机制不需要调用    存取方法和变量实例就可以访问对象属性(即使属性用@private修饰仍然可以访问,很黄很暴力,破坏封装性)。本质上讲,键-    值编码定义了你的程序存取方法要实现的样式及方法签名。
        在应用程序中实现键-值编码兼容性是一项重要的设计原则。存取方法可以加强合适的数据封装,而键-值编码方法在多数情    况下可简化程序代码。
        键-值 编码方法在Objective-C非标准协议(类目)NSKeyValueCoding 中被声明,默认的实现方法由NSObject提供。
        键值编码支持带有对象值的属性,同时也支持纯数值类型和结构。非对象参数和返回类型会被识别并自动封装/解封。

      2.KVC的基本用法
        设置和访问:
       键、值编码中的基本调用包括 - valueForKey:  和 - setValue:  forKey:  这两个方法,他们以字符串的形式向对象发送消    息,字符串是我们关注属性的关键。
   看代码中具体怎么使用:现在我们有个Person类,Book类,

<span style="font-family:SimHei;font-size:14px;">//Person.h
#import <Foundation/Foundation.h>
@class Book;
@interface Person : NSObject{
    @private
    NSString *_name;
}
//@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) Book *book;
- (instancetype)initWithName:(NSString *)name;
@end
</span>

<span style="font-family:SimHei;font-size:14px;">#import "Person.h"
#import "Book.h"
@implementation Person

- (instancetype)initWithName:(NSString *)name{
    if (self = [super init]) {
        _name = name;
    }
    return self;
}
</span>


    在ViewController中写如下代码:
<span style="font-family:SimHei;font-size:14px;">- (void)viewDidLoad {
    [super viewDidLoad];
    Person *p1 = [[Person alloc] initWithName:@"Jack"];
    Person *p2 = [[Person alloc] init];
    NSString *name0 = [p1 valueForKey:@"name"];
    NSString *name1 = [p1 valueForKeyPath:@"name"];

    [p2 setValue:@22 forKey:@"age"];
    NSInteger age = [[p2 valueForKey:@"age"] integerValue];

    NSLog(@"name0 : %@ name1 : %@", name0, name1);
    NSLog(@"p2's age : %ld", age);

}
</span>

    运行结果
<span style="font-family:SimHei;font-size:14px;">2015-05-02 20:36:34.803 review[1873:122845] name0 : Jack name1 : Jack
2015-05-02 20:36:34.804 review[1873:122845] p2's age : 22
</span>

    可以看到,通过-setValue: ForKey: 为p2 的age 设了值,通过 valueForKey: 或者 valueForKeyPath 能够访问到Person的属性name的值。
    KVC在设置或访问属性的值时,先看是否有setter getter方法,如果不存在,将查找内部是否有_name或者name实例变量。
    ForKey: 与 ForKeyPath:区别
    ForkeyPath 可以为支持指定路径,用『点』号隔开
    在viewDidLoad中添加如下代码:
<span style="font-family:SimHei;font-size:14px;">Book *book1 = [[Book alloc] init];
p1.book = book1;
[p1 setValue:@"葵花宝典" forKeyPath:@"book.name"];
NSString *bookName = [p1 valueForKeyPath:@"book.name"];
NSLog(@"bookName : %@", bookName);
</span>

    运行结果:
<span style="font-family:SimHei;font-size:14px;">2015-05-02 21:07:47.031 review[2068:132141] name0 : Jack name1 : Jack
2015-05-02 21:07:47.033 review[2068:132141] p2's age : 22
2015-05-02 21:07:47.034 review[2068:132141] bookName : 葵花宝典
</span>

    通过 【点】号 .属性 可以指定路径 访问任意的属性

  KVC的其他用法:
<span style="font-family:SimHei;font-size:14px;">    book1.price = 34.9;
    Book *book2 = [[Book alloc] init];
    book2.name = @"jiuyinzhenjing";
    book1.price = 56.5;
    Book *book3 = [[Book alloc] init];
    book3.name = @"rulaishenzhang";
    book3.price = 79.0;
    p1.books = @[book1, book2, book3];
    NSString *names = [p1 valueForKeyPath:@"books.name"];
    NSLog(@" names : %@", names);
    float sumPrice = [[p1 valueForKeyPath:@"books.@sum.price"] floatValue];
    NSLog(@"sumPrice : %f", sumPrice);</span>
运行结果:
<span style="font-family:SimHei;font-size:14px;">2015-05-02 21:25:49.090 review[2168:137783] name0 : Jack name1 : Jack
2015-05-02 21:25:49.092 review[2168:137783] p2's age : 22
2015-05-02 21:25:49.092 review[2168:137783] bookName : kuihuabaodian
2015-05-02 21:25:49.092 review[2168:137783] names : (
    kuihuabaodian,
    jiuyinzhenjing,
    rulaishenzhang
)
2015-05-02 21:25:49.093 review[2168:137783] sumPrice : 135.500000
</span>

    二、KVO
       KVO( Key Value Observing), 直译为:基于键值观察者。它提供一种机制,当指定的对象的属性被修改后,则对象就会接     受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
    你可以观察任意对象属性,包括简单属性,对一或者对多关系。对多关系的观察者将会被告知发生变化的类型-也就是任意,发生     变化的对象。 
      KVO的基本用法:
注册观察者、接收变更通知、移除观察者。
1.注册观察者:
[p1 addObserver:book1 forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

[p1 setValue:@"QQ" forKey:@"name"];


2.当被观察的属性的值改变时,就会调用观察者的如下方法:(写在Book.m中)

<span style="font-family:SimHei;font-size:14px;">- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    NSLog(@" %@   %@   %@",object, keyPath, change);
}
</span>

3.移除观察者。
<span style="font-family:SimHei;font-size:14px;">[p1 removeObserver:book1 forKeyPath:@"name"];
</span>

       KVO的底层实现机制:
KVO底层是由runtime 机制实现的。
当被观察者的属性值发生变化时,runtime 会自动为被观察者生产一个子类,KVONotifying父类名,生成的子类中有setter方法,调用这个setter方法,这个setter方法中还会调用两个方法,在这个两个方法之间调用了
<span style="font-family:SimHei;font-size:14px;">- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context</span>
方法;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值