015-KVC键值编码
一、基本知识
1.概述
KVC(Key-value-coding)键值编码。指的是在iOS开发中,可以允许开发者通过Key来直接访问对象的属性,或者给对象的属性赋值,而不需要明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性,而不是在编译时确定。
2.原理
无论在Swift中,还是Objective-C,KVC的定义都是对NSObject的扩展来实现的。所以对于继承自NSObject的类型,也就是几乎所有的Objective-C对象都能使用KVC。
1)外界调用NSObject对象的设置&取值方法(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;
2)NSObject对象内部需要重写的方法:
// 返回YES:表示是模糊搜索(如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员) // 返回NO:表示开发者不希望使用KVC,那么这个时候必须在NSObject对象中去实现对应属性的setter和getter方法 + (BOOL)accessInstanceVariablesDirectly; // KVC提供属性值正确性验证的API // 它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因 - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; // 这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; // 通过key获取value的时候,如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法 - (nullable id)valueForUndefinedKey:(NSString *)key; // 给key赋值value的时候,如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法 - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key; // 如果你在SetValue方法时给Value传nil,则会调用这个方法 - (void)setNilValueForKey:(NSString *)key; // 输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典 - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
3)原理图

二、代码实例
// Dog.h文件 #import <Foundation/Foundation.h> @interface Dog : NSObject @end // Dog.m文件 #import "Dog.h" @implementation Dog { NSString *_name; int _store; } #pragma mark - 如果accessInstanceVariablesDirectly方法返回NO,说明开发者不希望使用KVC,那么就要实现setter和getter方法 #if 0 -(void)setName:(NSString*)name { aName = name; } -(NSString*)getName { return aName; } #endif + (BOOL)accessInstanceVariablesDirectly { return YES; } #pragma mark - 调用setValue:forKey:方法时,如果找不到key有关的字段或者属性时就会执行 - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"%@对象中不存在%@属性,【%@ : %@】", [self class], key, key, value); } #pragma mark - 调用setValue:forKey:方法时,如果对象的key为基本数据类型时,所传参数value为nil就会执行 // 如果属性为基本数据类型(int、float、double)时,如果设置一个nil,就异常,就会执行 - (void)setNilValueForKey:(NSString *)key { NSLog(@"传值为nil的key:%@", key); } #pragma mark - 调用valueForKey:方法时,如果找不到key有关的字段或者属性时就会执行 - (id)valueForUndefinedKey:(NSString *)key { NSLog(@"%@对象中不存在%@属性", [self class], key); return nil; } @end // ViewController.m文件 #import "ViewController.h" #import "Dog.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Dog *dog = [Dog new]; [dog setValue:@"18" forKey:@"age"]; NSString *age = [dog valueForKey:@"age"]; NSLog(@"age = %@", age); [dog setValue:nil forKey:@"store"]; } @end
打印输出:
2017-11-02 14:07:24.069590+0800 KVCDemo[27358:3487322] Dog对象中不存在age属性,【age : 18】
2017-11-02 14:07:24.069736+0800 KVCDemo[27358:3487322] Dog对象中不存在age属性
2017-11-02 14:07:24.069753+0800 KVCDemo[27358:3487322] age = (null)
2017-11-02 14:07:24.069882+0800 KVCDemo[27358:3487322] 传值为nil的key:store

浙公网安备 33010602011771号