本文转载 李朴之先生博客 http://blog.csdn.net/pucker/article/details/7413280

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

一、KVC

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

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

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

  1. @interface ClassA : NSObject
  2. @property (nonatomic) int p1;
  3. @property (nonatomic) int p2;
  4. @property (nonatomic) int p3;
  5. - (int)getValueByPropertyName:(NSString*)pName;
  6. @end
  7. @implementation ClassA
  8. @synthesize p1 = _p1, p2 = _p2, p3 = _p3;
  9. ...
  10. - (int)getValueByPropertyName:(NSString*)pName
  11. {
  12. if([pName isEqualToString:@"p1"])
  13. {
  14. return self.p1;
  15. }
  16. else if([pName isEqualToString:@"p2"])
  17. {
  18. return self.p2;
  19. }
  20. else if([pName isEqualToString:@"p3"])
  21. {
  22. return self.p3;
  23. }
  24. return 0;
  25. }
  26. @end

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

  1. - (int)getValueByPropertyName:(NSString*)pName
  2. {
  3. NSNumber* pNumber = [self valueForKey:pName];
  4. return [pNumber intValue];
  5. }

这里有几点需要注意,首先这里的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:,我们就可以在一条语句中接连调用制定的属性。请看下面的例子:

  1. @interface Product : NSObject
  2. @property NSString* name;
  3. @end
  4. @implementation Product
  5. @synthesize name = _name;
  6. - (void)dealloc
  7. {
  8. self.name = nil;
  9. [super dealloc];
  10. }
  11. @end
  12. @interface Manufacturer : NSObject
  13. @property Product* product;
  14. @end
  15. @implementation Manufacturer
  16. @synthesize product = _product;
  17. -(void)dealloc
  18. {
  19. self.product = nil;
  20. [super dealloc];
  21. }
  22. @end
  23. int main(int argc, const char * argv[])
  24. {
  25. @autoreleasepool
  26. {
  27. Manufacturer* apple = [[[Manufacturer alloc] init] autorelease];
  28. Product* iPhone4S = [[[Product alloc] init] autorelease];
  29. iPhone4S.name = @"iPhone 4S";
  30. apple.product = iPhone4S;
  31. Manufacturer* micro$oft = [[[Manufacturer alloc] init] autorelease];
  32. Product* win8 = [[[Product alloc] init] autorelease];
  33. win8.name = @"Windows 8";
  34. micro$oft.product = win8;
  35. NSArray* manufacturerArray = [NSArray arrayWithObjects:apple, micro$oft, nil];
  36. NSArray* productNameArray = [manufacturerArray valueForKeyPath:@"product.name"];
  37. NSLog(@"productNameArray:\n%@", productNameArray);
  38. }
  39. return 0;
  40. }

首先程序定义了两个类Product与Manufacturer,分别定义商品与制造商。Manufacturer类定义了一个product属性,Product类定义了name属性。在main函数中,我们创建了两个制造商苹果和微软,以及两个商品iPhone4S和Win8,并设置好他们之间的关系。然后程序将两个制造商放入数组中,在数组上调用valueForKeyPath:方法并传入键值链@"product.name"。于是数组首先执行valueForKey:@"product",它会在每个数组成员上调用product属性,获取每个制造商的商品,然后再在每个商品上调用valueForKey:@"name",获取每个制造商的每个商品的名称,并将结果放到另一个数组中。上述程序的输出结果为:

  1. productNameArray:
  2. (
  3. "iPhone 4S",
  4. "Windows 8"
  5. )

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

Objective-C中的KVC与KVO(上)的更多相关文章

  1. iOS中关于KVC与KVO知识点

    iOS中关于KVC与KVO知识点 iOS中关于KVC与KVO知识点  一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NSObject类实现的NSKeyValueCodin ...

  2. iOS开发中KVC、KVO简介

    在iOS开发中,KVC和KVO是经常被用到的.可以使用KVC对对象的属性赋值和取得对象的属性值,可以使用KVO监听对象属性值的变化.简单介绍一下KVC和KVO. 一:键值编码(KVC) KVC,全称 ...

  3. [转] iOS (OC) 中 KVC 与 KVO 理解

    转自: http://magicalboy.com/kvc_and_kvo/ KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value ...

  4. 【原】iOS中KVC和KVO的区别

    在iOS开发中经常会看到KVC和KVO这两个概念,比较可能混淆,特地区分一下 KVC(Key Value Coding) 1> 概述 KVC:Key Value Coding,键值编码,是一种间 ...

  5. iOS - 详细理解KVC与KVO

    详细理解KVC与KVO 在面试的时候,KVC与KVO有些时候还是会问到的,并且他们都是Objective C的关键概念,在这里我们先做一个简单地介绍: (一)KVC: KVC即指:NSKeyValue ...

  6. KVC 与 KVO 理解

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

  7. KVC 与 KVO 理解-b

    KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...

  8. KVC与KVO的理解

    KVC与KVO是Objective C的关键概念. Key—Value Coding (KVC) 即是指NSKeyValueCoding,一个非正式的Protocol,提供一种机制间接访问对象的属性. ...

  9. KVC与KVO理解

    转载:https://magicalboy.com/kvc_and_kvo/ KVC 与 KVO 理解 KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲 ...

随机推荐

  1. calloc内存分配函数

    calloc是一个C语言函数 函数名: calloc void *calloc(unsigned n,unsigned size): 功 能: 在内存的动态存储区中分配n个长度为size的连续空间,函 ...

  2. php结合msf反弹内网shell

    感谢: perl6大佬分享的姿势. MSF: msf > use payload/php/bind_phpmsf exploit(handler) > set PAYLOAD payloa ...

  3. 高速掌握Lua 5.3 —— 扩展你的程序 (1)

    Q:怎样在C中将Lua作为配置文件语言使用? A: "config.lua"文件里: -- window size width = 200 height = 300 "m ...

  4. nginx的centos和rhel的yum配置安装

    Official Red Hat/CentOS packages To add NGINX yum repository, create a file named /etc/yum.repos.d/n ...

  5. C++中static_cast, dynamic_cast使用方法

    前言 Android的Framework层源代码中有非常多强制类型转换函数的调用.写惯了C代码的人一般都习惯以下这样的强制转换方式: double a = 89; int b = (int)a; 可是 ...

  6. flv网页视频播放

    今天需要用到网页视频播放功能,找了一下,发现flowplayer很好用,写了个dome需要的同学,去下载咯 http://download.csdn.net/detail/jine515073/770 ...

  7. mvn 仓库地址修改

    默认仓库的存储位置 Maven缺省的本地仓库路径为${user.home}/.m2/repository具体如下图 自定义修改仓库的存储位置: 可改变默认的 .m2 目录下的默认本地存储库文件夹通过修 ...

  8. 用 phpize 编译共享 PECL 扩展库

    有时候不能用 pecl 安装命令.这可能是因为在防火墙后面,或者是因为想要安装的扩展库还没有 PECL 兼容的包,例如 SVN 中尚未发布的扩展库.如果要编译这种扩展库,可以用更底层的编译工具来手工进 ...

  9. [mysql] 随机查询 效率比较

    select primary_count as primaryCount, primary_score as primaryScore, junior_count as juniorCount, ju ...

  10. vector、map删除当前记录

    map<string, string> sMap; map<string, string>::iterator iter; for(iter = sMap.begin();it ...