KVC 原理及自定义实现

时间:2021-09-09 16:09:58

一.  setValue: forKey: 赋值过程

1.首先寻找setter方法(两个)

   - setName:

   -setIsName:

2.然后再寻找成员变量

默认 + (BOOL)accessInstanceVariablesDirectly 返回YES;

  _key > _isKey > key > isKey 

3. 如果以上步骤没有找到key,则会报异常; 也可以重写方法,防止崩溃

  -setValue: forUndefinedKey:

 

二. valueForKey: 取值过程

1.getter方法(三个)

  -getKey

  -key

  -isKey

2.成员变量

  _key > _isKey > key > isKey 

3.上述没有,可重写,防止崩溃

  -valueForUndefinedKey

 

三. runtime  简单实现 KVC

新建一个NSObject 一个分类

 1 #import "NSObject+kvc.h"
 2 #import <objc/runtime.h>
 3 @implementation NSObject (kvc)
 4 - (void)xs_setValue:(id)value forKey:(NSString *)key{
 5     //key 需要合法
 6     if (key == nil || key.length == 0) {
 7         return;
 8     }
 9     //一.setter 方法
10     //调用相关setter方法(capitalizedString 首字母大写)
11     NSString *setKey = [NSString stringWithFormat:@"set%@:",[key capitalizedString]];
12     //调用
13     if ([self respondsToSelector:NSSelectorFromString(setKey)]) {
14         [self performSelector:NSSelectorFromString(setKey) withObject:value];
15         return;
16     }
17     NSString *setIsKey = [NSString stringWithFormat:@"setIs%@:",[key capitalizedString]];
18     if ([self respondsToSelector:NSSelectorFromString(setIsKey)]) {
19         [self performSelector:NSSelectorFromString(setIsKey) withObject:value];
20         return;
21     }
22     
23     //异常处理方法
24     if (![self.class accessInstanceVariablesDirectly]) {
25         NSException *exception = [NSException exceptionWithName:@"XSKVC Exception" reason:@"你返回了NO啊!" userInfo:nil];
26         @throw exception;
27         return;
28     }
29     //二.成员变量
30     unsigned int count = 0;
31     //获取所有成员变量
32     Ivar *ivars = class_copyIvarList([self class], &count);//解释:在C中,copy new create 在堆区开辟内存空间
33 //    NSMutableArray *array = [NSMutableArray array];
34 //    for (int i = 0; i<count; i++) {
35 //        Ivar ivar = ivars[i];
36 //        const char *name = ivar_getName(ivar);
37 //        NSString *keyName = [NSString stringWithUTF8String:name];
38 //        [array addObject:keyName];
39 //    }
40     //_key (按照优先级:_key > _isKey > key > isKey)
41     for (int i = 0; i<count; i++) {
42         Ivar ivar = ivars[i];
43         NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
44         if ([keyName isEqualToString:[NSString stringWithFormat:@"_%@",key]]) {
45             object_setIvar(self, ivar, value);
46             free(ivars);
47             return;
48         }
49     }
50     //_isKey
51     for (int i = 0; i<count; i++) {
52         Ivar ivar = ivars[i];
53         NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
54         if ([keyName isEqualToString:[NSString stringWithFormat:@"_is%@",key.capitalizedString]]) {
55             object_setIvar(self, ivar, value);
56             free(ivars);
57             return;
58         }
59     }
60     //key
61     for (int i = 0; i<count; i++) {
62         Ivar ivar = ivars[i];
63         NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
64         if ([keyName isEqualToString:[NSString stringWithFormat:@"%@",key]]) {
65             object_setIvar(self, ivar, value);
66             free(ivars);
67             return;
68         }
69     }
70     //isKey
71     for (int i = 0; i<count; i++) {
72         Ivar ivar = ivars[i];
73         NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
74         if ([keyName isEqualToString:[NSString stringWithFormat:@"is%@",key.capitalizedString]]) {
75             object_setIvar(self, ivar, value);
76             free(ivars);
77             return;
78         }
79     }
80     
81     //处理异常
82     [self setValue:value forUndefinedKey:key];
83     free(ivars);
84     
85 }