zoukankan      html  css  js  c++  java
  • iOS-KVC

    KVC

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

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

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

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

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

    [plain] view plaincopy
     
    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:,我们就可以在一条语句中接连调用制定的属性。请看下面的例子:

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

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

    [plain] view plaincopy
     
    1. productNameArray:  
    2. (  
    3.     "iPhone 4S",  
    4.     "Windows 8"  
    5. )  

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

  • 相关阅读:
    介绍一款jquery ui组件gijgo(含tree树状结构、grid表格),特点:简易、文档全清晰易懂、示例代码
    【未完待续】API接口
    表单中Readonly和Disabled的区别:readonly在get和post可传值到后端,disabled不可
    Newtonsoft.Json 转换DateTime类型为字符串时,串内部会有一个T。解决方案
    一种历史详细记录表,完整实现:CommonOperateLog 详细记录某用户、某时间、对某表、某主键、某字段的修改(新旧值
    js return falsee.preventDefault() 以及session
    bootstrape学习
    Redis的PHP操作手册
    PHP表单常用正则表达式(URL、HTTP、手机、邮箱等)
    大型网站架构演化
  • 原文地址:https://www.cnblogs.com/linxiu-0925/p/5071022.html
Copyright © 2011-2022 走看看