2018-03-29 KVC是怎么寻找Key的

KVC是怎么使用的,我相信绝大多数的开发者都很清楚,我在这里就不再写简单的使用KVC来设值和取值的代码了,首�先我们来探讨KVC在内部是按什么样的顺序来寻找key的。

设值

当调用setValue:属性值 forKey:@”name“的代码时,底层的执行机制如下:
• 程序优先调用set:属性值方法,代码通过setter方法完成设置。注意,这里的是指成员变量名,首字母大小写要符合KVC的命名规则,下同

• 如果没有找到setName:方法,KVC机制会检查+ (BOOL)accessInstanceVariablesDirectly方法有没有返回YES,默认该方法会返回YES,如果你重写了该方法让其返回NO的话,那么在这一步KVC会执行setValue:forUndefinedKey:方法,不过一般开发者不会这么做。所以KVC机制会搜索该类里面有没有名为的成员变量,无论该变量是在类接口处定义,还是在类实现处定义,也无论用了什么样的访问修饰符,只在存在以命名的变量,KVC都可以对该成员变量赋值。

• 如果该类即没有set:方法,也没有_成员变量,KVC机制会搜索_is的成员变量。

• 和上面一样,如果该类即没有set:方法,也没有_和_is成员变量,KVC机制再会继续搜索和is的成员变量。再给它们赋值。

• 如果上面列出的方法或者成员变量都不存在,系统将会执行该对象的setValue:forUndefinedKey:方法,默认是抛出异常。

如果开发者想让这个类禁用KVC里,那么重写+ (BOOL)accessInstanceVariablesDirectly方法让其返回NO即可,这样的话如果KVC没有找到set:属性名时,会直接用setValue:forUndefinedKey:方法。

下面我们来让代码来测试一下上面的KVC机制

@interface Dog : NSObject@end@implementation Dog
{
     NSString* toSetName;
    NSString* isName;
    //NSString* name;
    NSString* _name;
    NSString* _isName;
}// -(void)setName:(NSString*)name{//     toSetName = name;// }//-(NSString*)getName{//    return toSetName;//}
+(BOOL)accessInstanceVariablesDirectly{
    return NO;
}
-(id)valueForUndefinedKey:(NSString *)key{
    NSLog(@"出现异常,该key不存在%@",key);
    return nil;
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
     NSLog(@"出现异常,该key不存在%@",key);
}@endint main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Dog* dog = [Dog new];
        [dog setValue:@"newName" forKey:@"name"];
        NSString* name = [dog valueForKey:@"toSetName"];
        NSLog(@"%@",name);
    }
    return 0;
}

首先我们先重写accessInstanceVariablesDirectly方法让其返回NO,再运行代码(注意上面注释的部分),Xcode直接打印出

2016-04-15 15:52:12.039 DemoKVC[9681:287627] 出现异常,该key不存在name
2016-04-15 15:52:12.040 DemoKVC[9681:287627] 出现异常,该key不存在toSetName
2016-04-15 15:52:12.040 DemoKVC[9681:287627] (null)

这说明了重写+(BOOL)accessInstanceVariablesDirectly方法让其返回NO后,KVC找不到setName:方法后,不再去找name系列成员变量,而是直接调用setValue:forUndefinedKey:方法

所以开发者如果不想让自己的类实现KVC,就可以这么做。
下面那两个setter和getter的注释取消掉,再把

NSString* name = [dog valueForKey:@"toSetName"]; 换成 NSString* name = [dog valueForKey:@"name"];

XCode就可以正确地打印出正确的值了

2016-04-15 15:56:22.130 DemoKVC[9726:289258] newName

下面再注释掉accessInstanceVariablesDirectly方法,就能测试其他的key查找顺序了,为了节省篇幅,剩下的的KVC对于key寻找机制就不在这里展示了,有兴趣的读者可以写代码去验证。


本文作者:张元一

<上一篇 目录 下一篇>

你可能感兴趣的:(2018-03-29 KVC是怎么寻找Key的)