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

 

posted @ 2017-11-16 09:33  Frank9098  阅读(131)  评论(0)    收藏  举报