iOS : 了解下KVC

本文创作是为了知识温习和巩固,并希望对大家能够有所帮助。如果发现有任何错误,肯请大家留言指正,谢谢。

一、 KVC是什么?

KVC:即 Key-Value-Coding 是一种间接访问实例变量的形式 , 就是指 iOS 的开发中,可以允许开发者通过 Key 名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定。 iOS中所谓的黑魔法其实都是基于kvc来实现的

当调用 setValue:属性值 forKey:@”name“的代码,对于kvc应该怎么查找其实我们可以了解:

  • 程序优先调用setKey:属性值方法,代码通过setter方法完成设置。注意:这里的key是指成员变量名.
  • 如果没有找到setName:方法,KVC机制会检查

    +(BOOL)accessInstanceVariablesDirectly方法有没有返回 YES,默认该方法会返回 YES,如果你重写了该方法让其返回 NO 的话,那么在这一步 KVC 会执行 setValue:forUndefinedKey:方法,不过一般开发者不会这么做。所以 KVC 机制会搜索该类里面有没 有名为Key的成员变量,无论该变量是在类接口处定义,还是在类实现处定义,也无论用了什么样 的访问修饰符,只在存在以key命名的变量,KVC 都可以对该成员变量赋值。
  • 如果该类即没有setkey:方法,也没有_key成员变量,KVC机制会搜索_isKey的成员变量。
  • 和上面一样,如果该类即没有setKey:方法,也没有_key和_isKey成员变量,KVC机制再会继续 搜索key和 isKey的成员变量。再给它们赋值。
7007713d42184743a4a17b078c408597~tplv-k3u1fbpfcp-watermark.image.png

当调用 value:属性值 forKey:@”name“的代码,对于kvc应该怎么查找其实我们页可以简单的记忆了解和设置值基本上一样

  • 首先按getKey,key,isKey的顺序方法查找getter方法,找到的话会直接调用。如果是BOOL或者 Int 等值类型, 会将其包装成一个NSNumber对象。
  • 如果上面的getter没有找到,KVC则会查找countOfKey或KeyAtIndexes格式 的方法。如果 countOfKey方法和另外两个方法中的一个被找到,那么就会返回一个可以响应 NSArray 所有方法的代理集合,它是NSKeyValueArray(是NSArray的子类),调用这个代理集合的方法,或者说 给这个代理集合发送属于 NSArray 的方法,就会以countOfKey objectInKeyAtindex或KeyAtIndexes 这几个方法组合的形式调用。还有一个可选的 getKey: range方法。所以你想重新定义 KVC 的一些功 能,你可以添加这些方法,需要注意的是你的方法名要符合 KVC 的标准命名方法,包括方法签名。
  • 还没找到,查找countOfKey、enumeratorOfKey、memberOfKey格式的方法。如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合。
  • 还是没找到,如果类方法accessInstanceVariablesDirectly返回YES。那么按 _key,_isKey,key,iskey的顺序搜索成员名。
  • 再没找到,调用valueForUndefinedKey。
376b710cd82d4873aee53a6d2b0adddd~tplv-k3u1fbpfcp-watermark.image.png

KVC 访问顺序为:_key,_iskey,key,isKey 但是首先我们命名必须规范符合kvc的命名规则 前提下面的属性我们没有重新设置

// 表明键值编码方法是否应该直接访问相应的实例变量在发现没有一个属性的访问器方法。
+(BOOL)accessInstanceVariablesDirectly;

二、 KVC的常用方法

//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;       //通过Key来设值              
- (void)setValue:(nullable id)value forKey:(NSString *)key;
//通过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
//通过KeyPath来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  
//默认返回YES,表示如果没有找到Set方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
+ (BOOL)accessInstanceVariablesDirectly;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (nullable id)valueForUndefinedKey:(NSString *)key;
//和上一个方法一样,但这个方法是设值。
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;
//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
// 验证key对应的value是否可用
- (BOOL)validateValue:(inoutid*)ioValue forKey:(NSString*)inKey error:(outNSError**)outError;

三、KVC 异常处理

  1. KVC不允许你要在调用setValue:属性值 forKey:(或者keyPath)时对非对象传递一个nil的值。很简单,因为值类型是不能为nil的。如果你不小心传了,KVC会调用setNilValueForKey:方法。这个方法默认是抛出异常,所以一般而言最好还是重写这个方法。
  2. KVC不允许你要在调用setValue:属性值 forKey:(或者keyPath)时对不存在的key进行操作。 不然,会报错forUndefinedKey发生崩溃,重写forUndefinedKey方法避免崩溃。

KVC 不会自动调用健值验证的方法,如果需要我们自己需要手动来验证,上面的方法中最后一个方法就是对健值验证的方法,我们可以尝试下

        //Model生成对象
        Model *model = [[Model alloc] init];
        //通过KVC设值test的age
        NSNumber *age = @10;
        NSError* error;
        NSString *key = @"age";
        BOOL isValid = [model validateValue:&age forKey:key error:&error];
        if (isValid) {
            NSLog(@"键值匹配");
        }
        else {
            NSLog(@"键值不匹配");
        }
        //通过KVC取值age打印
        NSLog(@"model的年龄是%@", [test valueForKey:@"age"]);

四、KVC的使用

  • 1、动态取值设值
  • 2、通过KVC访问和改变私有变量
  • 3、Model和字典转换

你可能感兴趣的:(iOS : 了解下KVC)