分类: iOS平台
2014-03-21 11:26:15
User.h
@interface User : NSObject@property (nonatomic,copy) NSString *userId; @property (nonatomic,copy) NSString *name; @property (nonatomic,assign) NSInteger age; @property (nonatomic,copy) NSString *sex; - (id)initWithDictionary:(NSDictionary *)jsonDictionary; @end
User.m
@implementation User - (id)initWithDictionary:(NSDictionary *)jsonDictionary { self = [super init]; if(self){ [self setValuesForKeysWithDictionary:jsonDictionary]; } return self; }
我们看看jsonDictionary的内容:
"id" : "0", "name" : "jack", "age" : 15, "sex" : "male"
那执行完setValuesForKeysWithDictionary这个方法后User的属性就都会有值了。
仔细一点我们会发现 json 里面的id和属性里面的id不对应。(对于id这个键来说,这个类不兼容键值编码)
KVO提供了一个解决方法setValue:forUndefinedKey:用于处理上面的情况
我们需要实现setValue:forUndefinedKey:这个函数- (void)setValue:(id)value forUndefinedKey:(NSString *)key { if([key isEqualToString:@"id"]) self.userId = value; }
- (void)setValue:(id)value forUndefinedKey:(NSString *)key { if([key isEqualToString:@"id"]) self.userId = value; else [super setValue:value forKey:key]; }
然后基类里面也实现这个函数:
- (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"Undefined Key: %@", key); }这样就不会崩溃了。
最后看一下调用
NSDictionary *responseDictionary = [completedOperation responseJSON]; User *user = [[User alloc] initWithDictionary:responseDictionary];这就是KVO的能力,比之前自己去解析json做数据对应简单多了,同时如果服务器发送过来的json键名发生了变动,NSLog语句就会把未定义的键输出到控制台,而不会崩溃。
在派生类中添加用于处理深复制的方法也是非常好的。只需要覆盖NSCopying和NSMutableCopying中的方法就可以了
KVC还有很多有用的地方,简单了解一下:
key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名,并且必须以小写字母开头。Key path就是以“.”分隔的key,因为属性值也能包含属性。比如我们可以person这样的key,也可以有key.gender这样的key path。
获取属性值时可以通过valueForKey:的方法,设置属性值用setValue:forKey:。与此同时,KVC还对未定义的属性值定义了 valueForUndefinedKey:,你可以重载以获取你要的实现(补充下,KVC定义在NSKeyValueCoding的非正式协议里)。
在O-C 2.0引入了property,我们也可以通过.运算符来访问属性。下面直接看个例子:
@property NSInteger number; instance.number =3; [instance setValue:[NSNumber numberWithInteger:3] forKey:@"number"];
注意KVC中的value都必须是对象。
以上介绍了通过KVC来获取/设置属性,接下来要说明下实现KVC的访问器方法(accessor method)。Apple给出的惯例通常是:
-key:,以及setKey:(使用的name convention和setter/getter命名一致)。对于未定义的属性可以用setNilValueForKey:。