m
KVC(Key-value coding)键值编码,类似于map,提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制。
KVO(Key-value observing)键值观察,提供了一种当其它对象属性被修改的时候能通知当前对象的机制。
用法:
Model类
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; }
setValuesForKeysWithDictionary这个方法就是koc中的,用于匹配类中与字典key同名的属性,并赋值给属性,如果self是派生类,则会自动匹配派生类进行赋值。用这个来做json的映射看上面是很简单。
我们看看jsonDictionary的内容:
"id" : "0", "name" : "jack", "age" : 15, "sex" : "male"
那执行完setValuesForKeysWithDictionary这个方法后User的属性就都会有值了。
注意你的程序执行到setValuesForKeysWithDictionary会崩溃。
仔细一点我们会发现 json 里面的id和属性里面的id不对应。(对于id这个键来说,这个类不兼容键值编码)
KVO提供了一个解决方法setValue:forUndefinedKey:用于处理上面的情况
我们需要实现setValue:forUndefinedKey: 这个函数- (void)setValue:(id)value forUndefinedKey:(NSString *)key { if([key isEqualToString:@"id"]) self.userId = value; }
这样就没事了,然后顺便说说,其实可以做一个model的基类,然后基类里面去做这些处理,如果有特殊的key可以在子类实现:
子类:
- (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); }这样就不会崩溃了。
上面只是举个例子,一般开发建议Model基类里面去做上面的全部处理,然后子类做和自己相关的处理。
最后看一下调用
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:。