iOS开发之KVC和KVO

作者: Cyyyyyyyy | 来源:发表于2016-04-16 23:32 被阅读170次

KVC和KVO是Objective-C中经常被提到的两个术语。这篇文章将解释KVC和KVO的定义和最基本的用法,更多的信息请移步结尾部分的官方文档。


KVC(Key Value Coding)

定义

KVC的全称是Key Value Coding。这个名字会让人想到map的操作方式。实际上也正是这样,KVC可以让我们把NSObject对象当作一个map来用,即用字符串(Key)来访问NSObject对象的属性(Value)。

用法

我们只要使用Objective-C的property机制来定义成员变量,就可以使用KVC来访问属性了:

@interface BankAccount : NSObject
@property (nonatomic, assign) NSInteger balance;
@end

@interface Person : NSObject
- (instancetype)initWithName:(NSString*)name andBalance:(NSInteger)balance;

@property (nonatomic, strong) BankAccount *account;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSArray* friends;
@end

对于支持KVC的类,我们可以使用以下四个方法访问属性:

- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

直接看例子:

- (void) testKVC {
  // 初始化
  Person *zhangSan = [[Person alloc] initWithName:@"ZhangSan" andBalance:20];
  zhangSan.friends = @[@"LiSi", @"WangWu"];

  // 读取属性
  NSLog(@"%@", [zhangSan valueForKey:@"name"]); // ZhangSan
  // 名字包含KeyPath的方法支持用点语法访问属性的属性。
  // 注意,数值型的属性会自动被封包为NSNumber。
  NSLog(@"%@", [zhangSan valueForKeyPath:@"account.balance"]);  // 20

  // 同样,支持点语法设置属性。
  [zhangSan setValue:@150 forKeyPath:@"account.balance"]; 
    
  // 支持NSArray和NSDictionary这类代表一对多含义的属性
  NSLog(@"%@", [zhangSan valueForKey:@"friends"]);  // 输出[LiSi, WangWu] 
}

用途

因为系统提供的类都支持KVC,所以我们可以用KVC的方式来设置SDK未暴露出来的属性,比如修改UITextField的占位符的颜色。(这种做法依赖了系统的内部的实现,应该尽量避免):

[self.textfield setValue:[UIColor greyColor] forKeyPath:@"_placeholderLabel.textColor"]; 

我们还可以让控件的标识和数据对象的属性完全一样,使用KVC就可以节省大量的判断逻辑。下面是官方文档里的例子:

// 不用KVC
- (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row {
  ChildObject *child = [childrenArray objectAtIndex:row];
  if ([[column identifier] isEqualToString:@"name"]) {
    return [child name];
  }
  if ([[column identifier] isEqualToString:@"age"]) {
    return [child age];
  }
  if ([[column identifier] isEqualToString:@"favoriteColor"]) {
    return [child favoriteColor];
  }
  // And so on.
}

// 用KVC
- (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row {
  ChildObject *child = [childrenArray objectAtIndex:row];
  return [child valueForKey:[column identifier]];
}

更多的情况下,KVC是被用作别的技术的基础,比如下面的KVO。


KVO(Key Value Observing)

定义

KVO的全称是Key Value Observing。它是一种基于KVC的观察者模式的实现。如果不用KVO,我们要让一个类的属性实现观察者模式,得给这个类加上AddObserver/RemoveObserver方法,得在这个类里加一个数组保存所有的Observers,得在属性值变化的时候通知所有的Observer。虽然逻辑简单,但总归得折腾一会。
而有了KVO,我们可以使用很少的代码用上观察者模式了。

用法

@interface BankAccount : NSObject
@property (nonatomic, assign) NSInteger balance;
@end

@interface Person : NSObject
@property (nonatomic, strong) BankAccount *account;
@end

@implementation Person
 - (instancetype)init {
  ...   
  // 注册Observer:
  [self.account addObserver:self
                 forKeyPath:@"balance"
                    options:NSKeyValueObservingOptionNew |
                            NSKeyValueObservingOptionOld
                    context:nil];
  ...
}

- (void)dealloc {
  // 不要忘了removeObserver  
  [self.account removeObserver:self forKeyPath:@"balance"];
}

  // 属性变化的回调方法:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"balance"]) {
        NSLog(@"Balance was %@.", change[NSKeyValueChangeOldKey]);
        NSLog(@"Balance is %@ now.", change[NSKeyValueChangeNewKey]);
    }
}
@end

- (void)testKVO {
  Person *zhangSan = [[Person alloc] initWithName:@"ZhangSan" andBalance:20];
  // 无论是用点语法还是KVC的方法都会触发回调:
  zhangSan.account.balance = 150;
  [zhangSan setValue:@250 forKeyPath:@"account.balance"]; 
}

参考文档

Key-Value Coding Programming Guide
Key-Value Observing Programming Guide

相关文章

  • KVC 和 KVO

    iOS-KVC和KVO精炼讲解(干货)KVC 和 KVOiOS开发系列--Objective-C之KVC、KVO细...

  • KVC

    iOS 如何使用KVC iOS开发UI篇—Kvc简单介绍 iOS开发系列--Objective-C之KVC、KVO

  • KVC

    KVC原理剖析 - CocoaChina_让移动开发更简单 iOS开发底层细究:KVC和KVO底层原理 | iOS...

  • KVC、KVO

    IOS开发系列--Objective-C之KVC、KVO - KenshinCui - 博客园

  • 知识点3

    26. 什么是KVC和KVO? KVO: iOS开发-KVO的奥秘 http://www.jianshu.com/...

  • ReactiveCocoa相关

    随手记录: 1、iOS开发系列--Objective-C之KVC、KVO 2、ReactiveCocoa初探

  • iOS日记15-KVC

    1.iOS开发技巧系列---详解KVC 2.漫谈 KVC 与 KVO 3.KVC/KVO原理详解及编程指南 关键点...

  • 4.iOS开发之KVC

    iOS的日常开发中KVC与KVO还是使用率蛮高的,整理一下。KVC和KVO都是基于OC的动态特性和Runtime机...

  • 5.iOS开发之KVO

    iOS的日常开发中KVC与KVO还是使用率蛮高的,整理一下。KVC和KVO都是基于OC的动态特性和Runtime机...

  • 什么是KVC

    在iOS开发过程中,我们经常会听到或者用到KVO/KVC,但是对于什么是KVO和KVC,我们可能没有那么了解。下面...

网友评论

    本文标题:iOS开发之KVC和KVO

    本文链接:https://www.haomeiwen.com/subject/eozglttx.html