KVC

KVC 为核心方法,闭源,没有源码,只能猜测。为了方便理解,自己根据官方文档的描述,实现了一个简单的KVC,所以是不安全的,只作为理解学习使用。(在导入第三方框架的时候,需要考虑是否有导入的必要性,权衡利弊)

 

KVC官方文档

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i

 

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

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/coolcold/p/12027653.html