[TOC]
本章主要探索 KVC 的取值和赋值过程
探索过程来源于官方文档:About Key-Value Coding
一、赋值过程的探索
准备条件
-
SRPerson
类
// 成员变量
{
@public
NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
- 探索 key:
name
[person setValue:@"setter" forKey:@"name"];
NSLog(@"%@-%@-%@-%@", person->_name, person->_isName, person->name, person->isName);
NSLog(@"%@-%@-%@", person->_isName, person->name, person->isName);
NSLog(@"%@-%@", person->name, person->isName);
NSLog(@"%@", person->isName);
1.1 _key
- KVC 最先找到的是
_key
,也就是_name
1.2 _isKey
{
@public
// NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
- 如果没有找到
_key
,则会找_isKey
1.3 key
{
@public
// NSString* _name;
// NSString* _isName;
NSString* name;
NSString* isName;
}
- 如果没有找到
_key
和_isKey
,则会找key
1.4 isKey
{
@public
// NSString* _name;
// NSString* _isName;
// NSString* name;
NSString* isName;
}
- 当上面都没找到时,会去找
isKey
setter 方法的流程(setter方法在成员变量之前)
- setKey 流程方法
@implementation SRPerson
//MARK: - setKey. 的流程分析
- (void)setName:(NSString *)name{
NSLog(@"%s - %@",__func__,name);
}
- (void)_setName:(NSString *)name{
NSLog(@"%s - %@",__func__,name);
}
- (void)setIsName:(NSString *)name{
NSLog(@"%s - %@",__func__,name);
}
@end
- 成员变量
{
@public
NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
- 测试代码
// 1. KVC - 设置值的过程
[person setValue:@"setter" forKey:@"name"];
NSLog(@"%@-%@-%@-%@", person->_name, person->_isName, person->name, person->isName);
NSLog(@"%@-%@-%@", person->_isName, person->name, person->isName);
NSLog(@"%@-%@", person->name, person->isName);
NSLog(@"%@", person->isName);
setKey
- setter 方法在 成员变量的前面,最先查找的 setter 方法是:
setKey
_setKey
- 其次是:
_setKey
setIsKey
- 最后是:
setIsKey
二、取值过程的探索
准备条件
- 成员变量
{
@public
NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
- 测试代码
// 2. KVC - 取值过程
person->_name = @"_name";
person->_isName = @"_isName";
person->name = @"name";
person->isName = @"isName";
NSLog(@"取值 : %@", [person valueForKey:@"name"]);
2.1 _key
- 成员变量
{
@public
NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
2.2 _isKey
- 成员变量
{
@public
// NSString* _name;
NSString* _isName;
NSString* name;
NSString* isName;
}
2.3 key
- 成员变量
{
@public
// NSString* _name;
// NSString* _isName;
NSString* name;
NSString* isName;
}
isKey
- 成员变量
{
@public
// NSString* _name;
// NSString* _isName;
// NSString* name;
NSString* isName;
}
三、accessInstanceVariablesDirectly
方法
这个方法是提供:开启或关闭成员变量的赋值
- YES:允许成员变量赋值
- NO: 不允许成员变量赋值
+ (BOOL)accessInstanceVariablesDirectly{
return NO;
}
当返回 NO 时,对成员变量赋值,会有什么结果?
从截图中可以看出来,程序闪退,提示 name 是未定义的 key
四、KVC 流程总结
4.1 KVC原理:setValue 调用过程
-
先会查找 setter 方法
- 查找顺序:
setKey->_setKey->setIsKey
- 查找顺序:
-
如果setter方法没找到,就找实例变量
-
accessInstanceVariablesDirectly
返回 YES - 查找顺序:
_key->_isKey->key->isKey
- 如果找到,直接给这些实例变量 设值
-
如果setter方法和实例变量都没找到,则执行
setValue:forUndefinedKey:
方法
4.2 KVC原理:valueForKey 调用过程
-
先会查找 getter 方法
- 查找顺序:
getKey->key->isKey->_key
- 如果找到,则调到第5步
- 查找顺序:
-
判断是否是 NSArray
相当于获取一个 pens 的数组
person.arr = @[@"pen0", @"pen1", @"pen2", @"pen3"]; NSArray *array = [person valueForKey:@"pens"];
通过方法映射将数组的值返回
- countOf
- (NSUInteger)countOfPens{ NSLog(@"%s",__func__); return [self.arr count]; }
- objectIn
AtIndex:
- (id)objectInPensAtIndex:(NSUInteger)index { NSLog(@"%s",__func__); return [NSString stringWithFormat:@"pens %lu", index]; }
- countOf
判断是否是 NSSet
集合的方法也类似,这里不需要了解的特别清楚,知道有这么一回事就行了-
非集合类型
-
accessInstanceVariablesDirectly
返回 YES - 查找顺序:
_key->_isKey->key->isKey
- 如果找到,直接获取实例变量的值,然后继续执行步骤5
-
-
对象指针
- 如果检索到的属性是对象指针,则只需返回结果
- 如果值是NSNumber支持的标量类型,则将其存储在NSNumber实例中并返回。
- 如果结果是不被NSNumber支持的标量类型,转换成NSValue对象并返回它。
如果以上都没有找到,则执行
valueForUndefinedKey:
方法