03--KVC/KVO本质02--KVC 取值&赋值过程

[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
_key

1.2 _isKey

{
    @public
//    NSString* _name;
    NSString* _isName;
    NSString* name;
    NSString* isName;
}
  • 如果没有找到 _key,则会找 _isKey
_isKey

1.3 key

{
    @public
//    NSString* _name;
//    NSString* _isName;
    NSString* name;
    NSString* isName;
}
  • 如果没有找到 _key_isKey,则会找 key
key

1.4 isKey

{
    @public
//    NSString* _name;
//    NSString* _isName;
//    NSString* name;
    NSString* isName;
}
  • 当上面都没找到时,会去找 isKey
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

  • 其次是:_setKey
_setKey

setIsKey

  • 最后是: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;
}
_key

2.2 _isKey

  • 成员变量
{
    @public
    // NSString* _name;
    NSString* _isName;
    NSString* name;
    NSString* isName;
}
_isKey

2.3 key

  • 成员变量
{
    @public
    // NSString* _name;
   // NSString* _isName;
    NSString* name;
    NSString* isName;
}
key

isKey

  • 成员变量
{
    @public
    // NSString* _name;
   // NSString* _isName;
   // NSString* name;
    NSString* isName;
}
isKey

三、accessInstanceVariablesDirectly 方法

这个方法是提供:开启或关闭成员变量的赋值

  • YES:允许成员变量赋值
  • NO: 不允许成员变量赋值
+ (BOOL)accessInstanceVariablesDirectly{
    return NO;
}

当返回 NO 时,对成员变量赋值,会有什么结果?

从截图中可以看出来,程序闪退,提示 name 是未定义的 key

crash

四、KVC 流程总结

4.1 KVC原理:setValue 调用过程

  1. 先会查找 setter 方法

    • 查找顺序:setKey->_setKey->setIsKey
  2. 如果setter方法没找到,就找实例变量

    • accessInstanceVariablesDirectly 返回 YES
    • 查找顺序:_key->_isKey->key->isKey
    • 如果找到,直接给这些实例变量 设值
  3. 如果setter方法和实例变量都没找到,则执行 setValue:forUndefinedKey: 方法

4.2 KVC原理:valueForKey 调用过程

  1. 先会查找 getter 方法

    • 查找顺序:getKey->key->isKey->_key
    • 如果找到,则调到第5步
  2. 判断是否是 NSArray

    相当于获取一个 pens 的数组

    person.arr = @[@"pen0", @"pen1", @"pen2", @"pen3"];
    NSArray *array = [person valueForKey:@"pens"];
    

    通过方法映射将数组的值返回

    • countOf
    - (NSUInteger)countOfPens{
        NSLog(@"%s",__func__);
        return [self.arr count];
    }
    
    • objectInAtIndex:
    - (id)objectInPensAtIndex:(NSUInteger)index {
        NSLog(@"%s",__func__);
        return [NSString stringWithFormat:@"pens %lu", index];
    }
    
  3. 判断是否是 NSSet
    集合的方法也类似,这里不需要了解的特别清楚,知道有这么一回事就行了

  4. 非集合类型

    • accessInstanceVariablesDirectly 返回 YES
    • 查找顺序:_key->_isKey->key->isKey
    • 如果找到,直接获取实例变量的值,然后继续执行步骤5
  5. 对象指针

    • 如果检索到的属性是对象指针,则只需返回结果
    • 如果值是NSNumber支持的标量类型,则将其存储在NSNumber实例中并返回。
    • 如果结果是不被NSNumber支持的标量类型,转换成NSValue对象并返回它。
  6. 如果以上都没有找到,则执行 valueForUndefinedKey: 方法

你可能感兴趣的:(03--KVC/KVO本质02--KVC 取值&赋值过程)