KVC 为核心方法,闭源,没有源码,只能猜测。为了方便理解,自己根据官方文档的描述,实现了一个简单的KVC,所以是不安全的,只作为理解学习使用。(在导入第三方框架的时候,需要考虑是否有导入的必要性,权衡利弊)
KVC官方文档
Key-value coding is a mechanism enabled by the NSKeyValueCoding informal protocol that objects adopt to provide indirect access to their properties.
翻译:KVC是对象提供的一种可以通过NSKeyValueCoding协议便捷的间接访问属性机制。
需要理解的内容:
iOS 成员变量,实例变量,属性变量的区别:
全部为成员变量
实例变量是一宗特殊的成员变量
@interface KVCViewController (){
@public
NSString *myName; //成员
UIButton *btn; //实例变量
id hell; //id 是一种特殊的 class 所以也是实例变量
}
属性系统会生成默认的setter + getter
GCC -> LLVM(编译器升级)
LLVM为没有匹配的实例变量属性,自动创建一个带下划线的成员变量
@sythesie namep = _namep; //自动生成setter getter
官方文档讲到KVC分为简单类型(但是并没有讲简单类型包括哪些,个人认为是int,number,string...)和复杂类型(array, set):
简单类型 --------------------------------------------------
setValue forKey流程:
查找调用顺序 set<Key>, _set<Key> 如果没有实现以上两个方法并且+ (BOOL)accessInstanceVariablesDirectly(返回NO崩溃) 返回YES --> 那么就会依次按 _<key>
, _is<Key>
, <key>
, or is<Key> 顺序查找成员变量并且赋值。
valueForKey查找流程:
查找调用顺序 get<Key>, <key>, is<Key>, or _<key> 下面是官方文档截图(很详细):
在使用value forkey过程中,经过自己验证发现以下查找逻辑(如果是简单的实例变量):
总的查找顺序是 get<Key>, <key>, is<Key>, or _<key>
1. 如果当前属性自动生成set get方法则系统会按照get<Key>, <key>顺序查找方法是否实现,不会查找后面is<Key>, <key>方法。
2. 如果当前是成员变量,则还是会按照get<Key>, <key>, is<Key>, or _<key>顺序查找调用(只调用其中一个方法)。
3. 如果四个方法都没实现并且+ (BOOL)accessInstanceVariablesDirectly(默认返回Yes) 返回NO系统崩溃,返回YES不会崩溃,值为null。
复杂实例变量:
NSArray->走第2步
NSSet(哈希,散列表)->走第3部。
代码:
#import "Person.h"
@implementation Person
#pragma mark - set相关
- (void)setName:(NSString *)name{
NSLog(@"%s",__func__);
}
- (void)_setName:(NSString *)name{
NSLog(@"%s",__func__);
}
- (void)setIsName:(NSString *)isName{
NSLog(@"%s",__func__);
}
#pragma mark - get相关
- (NSString *)getName{
NSLog(@"%s",__func__);
return NSStringFromSelector(_cmd);
}
- (NSString *)name{
NSLog(@"%s",__func__);
return NSStringFromSelector(_cmd);
}
- (NSString *)isName{
NSLog(@"%s",__func__);
return NSStringFromSelector(_cmd);
}
- (NSString *)_name{
NSLog(@"%s",__func__);
return NSStringFromSelector(_cmd);
}
#pragma mark - 关闭或开启实例变量赋值
//是否开启间接访问变量
+ (BOOL)accessInstanceVariablesDirectly{
return NO;
}
@end
复杂类型 --------------------------------------------------
数组:验证valueForKey发现以下逻辑
NSArray *arr = [p valueForKey:@"fxArray"]; // 动态成员变量
[arr containsObject:@"fxArray 0"];
//数组valueForKey 与 contaainsObject 都会会调用以下方法:
// 个数
- (NSUInteger)countOfFxArray {
return [self.array count];
}
//// 获取值
- (id) objectInFxArrayAtIndex:(NSUInteger)index {
return [NSString stringWithFormat:@"fxArray %lu", index];
}
集合
demo: https://github.com/531837586/fxDemo