Objective-C中的KVC与KVO(上)

原创 2012年03月30日 23:32:12

Objective-C中的KVC与KVO是两种比较重要的技术,这里简要介绍一下这两者的使用方法。

一、KVC

《iOS程序开发方法与实践》中介绍了KVC(Key–Value Coding,键值编码)的基本内容。

简要来说,KVC提供了一种在运行时而非编译时动态访问对象属性与成员变量的方式,也就是说,我们可以用字符串的内容作为属性名称或者成员变量名称进行访问。这种特性有些类似于其他高级编程语言中的反射。

举个例子,例如我们创建了一个类ClassA,其中定义了3个属性p1、p2和p3,以及1个实例方法getValueByPropertyName:,代码如下:

@interface ClassA : NSObject
@property (nonatomic) int p1;
@property (nonatomic) int p2;
@property (nonatomic) int p3;

- (int)getValueByPropertyName:(NSString*)pName;
@end

@implementation ClassA
@synthesize p1 = _p1, p2 = _p2, p3 = _p3;

...
- (int)getValueByPropertyName:(NSString*)pName
{
    if([pName isEqualToString:@"p1"])
    {
        return self.p1;
    }
    else if([pName isEqualToString:@"p2"])
    {
        return self.p2;
    }
    else if([pName isEqualToString:@"p3"])
    {
        return self.p3;
    }
    
    return 0;
}
@end

方法getValueByPropertyName:用于通过字符串来访问对应的属性值。如果我们想要向ClassA添加几个属性,那么这个方法就还需要添加几个else if语句。而如果使用KVC就会方便许多,代码如下:

- (int)getValueByPropertyName:(NSString*)pName
{
    NSNumber* pNumber = [self valueForKey:pName];
    return [pNumber intValue];
}

这里有几点需要注意,首先这里的valueForKey:方法用于以字符串调用对象的get属性方法,或者读取成员变量的值;与之相对的是setValue:forKey:,它用于以字符串调用对象的set属性方法,或者修改成员变量的值。第二点需要注意的是,对于基本数据类型,KVC方法会对基本数据类型进行封装(基本数据类型封装为NSNumber,其他结构体类型封装为NSValue)。这里的p1、p2、p3定义为int型,而valueForKey:方法返回的是NSNumber对象,需要再调用intValue取出其中的值。setValue:forKey:方法与之类似,接收NSNumber参数。第三,在使用KVC时,如果找不到字符串对应的属性和成员变量时会怎么样?此时会调用valueForUndefinedKey:或者setValue:forUndefinedKey:这两个方法,默认情况下会抛出异常。第四,默认情况下KVC方法能够直接访问类的私有成员变量,如果我们不想这样,可以重写accessInstanceVariablesDirectly方法,并令其返回NO(默认是返回YES)。KVC方法定义在NSKeyValueCoding类别中,该类别附加于NSObject类上,所以所有对象都具有这些方法。第五,在一些特殊的类的对象上调用KVC方法会有特别的效果。对于数组NSArray、集合NSSet,调用valueForKey:会对每个数组和集合成员调用valueForKey:,并返回新的数组或者集合。

在KVC中还有一种常用技术,称为键值链(Key Path)。键值链是用点将若干键相连的字符串,例如“manufacturer.product.name”。通过在对象上调用valueForKeyPath:或者setValue:forKeyPath:,我们就可以在一条语句中接连调用制定的属性。请看下面的例子:

@interface Product : NSObject
@property NSString* name;
@end

@implementation Product
@synthesize name = _name;

- (void)dealloc
{
    self.name = nil;
    [super dealloc];
}
@end

@interface Manufacturer : NSObject
@property Product* product;
@end

@implementation Manufacturer
@synthesize product = _product;

-(void)dealloc
{
    self.product = nil;
    [super dealloc];
}
@end

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

    @autoreleasepool
    {
        Manufacturer* apple = [[[Manufacturer alloc] init] autorelease];
        Product* iPhone4S = [[[Product alloc] init] autorelease];
        iPhone4S.name = @"iPhone 4S";
        apple.product = iPhone4S;
        
        Manufacturer* micro$oft = [[[Manufacturer alloc] init] autorelease];
        Product* win8 = [[[Product alloc] init] autorelease];
        win8.name = @"Windows 8";
        micro$oft.product = win8;
        
        NSArray* manufacturerArray = [NSArray arrayWithObjects:apple, micro$oft, nil];
        
        NSArray* productNameArray = [manufacturerArray valueForKeyPath:@"product.name"];
        NSLog(@"productNameArray:\n%@", productNameArray);
        
    }
    return 0;
}
首先程序定义了两个类Product与Manufacturer,分别定义商品与制造商。Manufacturer类定义了一个product属性,Product类定义了name属性。在main函数中,我们创建了两个制造商苹果和微软,以及两个商品iPhone4S和Win8,并设置好他们之间的关系。然后程序将两个制造商放入数组中,在数组上调用valueForKeyPath:方法并传入键值链@"product.name"。于是数组首先执行valueForKey:@"product",它会在每个数组成员上调用product属性,获取每个制造商的商品,然后再在每个商品上调用valueForKey:@"name",获取每个制造商的每个商品的名称,并将结果放到另一个数组中。上述程序的输出结果为:
productNameArray:
(
    "iPhone 4S",
    "Windows 8"
)

使用KVC的好处是非常灵活,但同时也丢失了编译时检查。

在下一篇中,我将会介绍KVO的使用方法。

OC学习篇之---KVC和KVO操作

前一篇文章我们介绍了OC中最常用的文件操作:http://blog.csdn.net/jiangwei0910410003/article/details/41875015,那么今天来看一下OC中的一...
  • jiangwei0910410003
  • jiangwei0910410003
  • 2014年12月13日 22:12
  • 15359

KVC 和 KVO 的一点理解

KVC 用 KVC 实现高阶消息传递 valueForKey: 有很多有用的特例,比如说 NSArray 和 NSSet 这样的容器类都覆盖了这个方法。valueForKey: 被传递...
  • chaoyuan899
  • chaoyuan899
  • 2015年03月29日 10:59
  • 4619

KVC/KVO底层实现原理

KVC: Key-value coding is a mechanism for indirectly accessing anobject’s attributes and relationship...
  • wzxq123
  • wzxq123
  • 2016年05月27日 17:15
  • 1786

ios中对KVO、KVC的一些理解

Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者,相当于设计模...
  • kuloveyouwei
  • kuloveyouwei
  • 2014年02月28日 15:25
  • 9366

KVC/KVO 进阶(一) 底层原理

导语 上篇文章介绍了一些KVC/KVO的简单用法,本篇介绍一下KVC/KVO的底层原理。 创建 person 和 car 类person.h@class Car; @interface Persi...
  • u014641631
  • u014641631
  • 2016年10月27日 15:32
  • 371

学习swift 《kvc和kvo的简单使用》

kvc和kvo我是对照着ios写的,有什么不对的地方多多指教 先建两个简单的model类,Animal类和dog类没有任何继承关系 如下: import UIKit class A...
  • sinat_34245894
  • sinat_34245894
  • 2017年08月07日 19:12
  • 190

iOS OC KVC KVO 实现原理详解

本文参考了如下文章:http://mobile.51cto.com/iphone-278413.htm http://blog.csdn.net/kesalin/article/details/81...
  • jeffasd
  • jeffasd
  • 2016年04月07日 13:46
  • 1249

关于 KVO 和 KVC 的一些总结 以及使用KVC进行字典和模型的互相转换

一直对KVO 和KVC都是停留在 只是知道的情况,从来没有尝试这在项目中使用,最近准备总结一下,在项目里面简单的使用一下 1、什么是KVO? KVO其实就是Key-Value-Observer,...
  • u011303663
  • u011303663
  • 2015年12月30日 17:58
  • 614

【iOS】KVC 和 KVO 的使用场景

Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property...
  • chenglibin1988
  • chenglibin1988
  • 2014年07月29日 10:25
  • 26020

iOS中KVC与KVO的区别

一、KVC与KVO *“KVC”:key value Coding(键值编码) *目的:间接的修改或获取对象的属性,降低程序(类与类)之间的耦合度. *“KV...
  • sevenquan
  • sevenquan
  • 2015年12月23日 15:33
  • 435
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Objective-C中的KVC与KVO(上)
举报原因:
原因补充:

(最多只允许输入30个字)