KVC基础
KVC是一种通过键值编码的方式间接访问对象属性的机制,可以通过字符串访问对应的属性方法或成员变量。
比如:我们经常使用的字典赋值就是依赖于KVC。
成员变量
成员变量通常是指那些基础类型或常量。
实例变量
是一种特殊的成员变量,我们通过Class类进行实例化出来的变量就是实例变量。
UIButton *btn;
id hello 是Oc一种特殊的class,不一定是实例变量
属性
默认setter和getter方法 苹果早期的编译器是GCC,后期升级编译器也就是我们现在使用LLVM。 当没有匹配实例变量的属性,LLVM就会自动创建一个带下划线的实例变量,并生成setter和getter方法.
KeyPath
除了可以对当前的属性进行赋值外,我们还可以对其对象更深层次的属性进行赋值。
@property (weak, nonatomic) IBOutlet UITextField *textFiled;
[self.textFiled setValue:[UIColor orangeColor] forKeyPath:@"_placeholderLabel.textColor"];
赋值和取值过程
取值过程:
KVC提供的getter默认方法valueForKey:,当给出参数key的时,进行方法调用,接下来是Getter内部执行流程如下:
一、普通类型
- get(Key)
- (Key)
- is(Key)
- _(Key) 按照以上的顺序的拼接进行实例方法的搜索,如果找到符合的方法 ,就调用对应的方法并拿出结果goto至第四步;反之,进行下一步操作。
二、集合类型
- 数组array
- countOf(Key)
- objectIn(Key)AtIndex:
- 集合set
- countOf(Key)
- enumeratorOf(Key)
- memeberOf(Key) 如果没有找到,则继续搜索其匹配的方法的,定义规则是按照以上集合类型顺序(先搜索array,再搜索set)。 如果找到其中的任意一个,则创建一个集合代理对象,该对象响应所有集合类型的方法并返回。反之,进行下一步操作。
三、accessInstaceVariablesDirectly 是否开启间接访问,默认返回YES
- _(Key)
- _is(Key)
- (Key)
- is(Key)
如果开启间接访问,会按照以上顺序的拼接方法进行搜索,如果发现对应的实例,则进下一步操作,反之,goto到第六步。
四、结果返回
- 对象则直接返回
- 基础数据类型,支持NSNumber的话,直接返回NSNumber类型
- 不支持NSNumber的基础数据类型,直接返回NSValue类型
五、没有找到 通过以上方法进行搜索,都没有匹配到对应的实例,则默认会调用valueForUndefineKey:方法并抛出异常。
赋值过程
两种类型
基础 setter 搜索模式
KVC提供的setter默认方法setValue:forKey:,当给出参数key和value的时,进行方法调用,接下来是setter内部执行流程如下:
- 首先会找set(Key): 或者 _set(Key)的拼接的setter,如果找到,调用这个方法并进行赋值操作,反之,进行下一步操作
- 判断是否间接访问 accessInstaceVariablesDirectly
- _(Key)
- _is(Key)
- (Key)
- is(Key) 如果开启间接访问,则会按照以上顺序进行拼接的实例变量,如果找到,将value赋值给实例变量
- 如果没有找到,就会报错,默认调用setValue:forUndefinedKey:方法并抛出异常
Mutable Arrays 搜索模式
此模式KVC提供默认实现方法mutableArrayValueForKey:,当给出key参数时, 集合类型
- 首先会找insertObject:in(Key)AtIndex: or insert(Key):atIndexes:和removeObjectFrom(Key)AtIndex: or remove(Key)AtIndexes:方法,如果找到返回一个代理对象来响应发送给NSMutableArray的组合消息;当对程序时行性能分析发现问题时,可以实现替换方法:removeObjectAtIndex: and removeObjectsAtIndexes:来进行处理。
- 如果没有找到可变数组方法,也没有找到访问器,查找一个set(Key)格式的方法,向mutableArrayValueForKey:的原始响应者发送set(Key):消息
- 如果没可变数组方法,也没有找到访问器,当开启间接访问accessInstanceVariablesDirectly,则查找一个命名为_(Key)或(Key)的实例变量,按这个顺序,如果找到实例变量,则返回一个代理对象。
- 如果都没有找到,刚返回一个可变集合代理对象。当它接收NSMutableArray消息时,发送一个setValue:forUndefineKey:给消息的原始对象并抛出NSUndefineKeyException异常。
注:还有NSMutableSet和NSMutableOrderedSet两种搜索模式步骤同上,只搜索和调用的方法不一样,具体可以参考官方文档:Key-Value Coding Programming Guide
KVC异常处理
根据KVC搜索流程,没有查找对应的key,则会调用对应的异常方法。异常方法的默认实现,在异常发生时会抛出一个NSUndefineKeyException的异常,并且应用闪退。 我们可以重写下面两个方法,根据业务需求处理KVC导致的异常
- (Nullable id)valueForUndefinedKey:(Nsstring *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
如果通过KVC给某个非对象的属性赋值nil时,此时KVC会调用属性所属对象的setNilValueForKey:方法,并抛出NSInvalidArgumentException的异常,并且应用闪退。 我们通过重写下面方法,在发生这种异常时进行处理。
- (void)setNilValueForKey:(NSString *)key {
if ([key isEqualToString:@"name"]) {
[self setValue:@"" forKey:@"age"];
} else {
[super setNilValueForKey:key];
}
}
以上部分内容参考: