zoukankan      html  css  js  c++  java
  • OC KVC

    ####NSObject(NSKeyValueCoding)

    #####Key相关

    //直接通过Key来取值
    - (nullable id)valueForKey:(NSString *)key;
    //通过Key来设值
    - (void)setValue:(nullable id)value forKey:(NSString *)key;
    
    //KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
    - (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
    
    //如果属性是一个NSMutableArray,那么可以用这个方法来返回。
    - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    
    //如果属性是一个NSMutableOrderedSet,那么可以用这个方法来返回。
    - (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
    
    //如果属性是一个NSMutableSet,那么可以用这个方法来返回。
    - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
    
    //如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
    - (nullable id)valueForUndefinedKey:(NSString *)key;
    
    //如果setKey不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
    - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
    
    // 如果你在SetValue方法时面给Value传nil,则会调用这个方法
    - (void)setNilValueForKey:(NSString *)key;
    复制代码

    ######Key设值

    当[obj setValue:@"老王" forKey:@"name"],底层的执行机制如下:

    1、程序优先调用set:属性值方法,代码通过setter方法完成设置。 2、如果没有找到setName:方法,会按照_key,_isKey,key,isKey的顺序搜索成员执行赋值;设置成NO就不这样搜索。(如果重写accessInstanceVariablesDirectly让其返回NO的话,那么在这一步KVC会执行setValue:forUndefinedKey:方法)。 3、如果上面列出的方法或者成员变量都不存在,系统将会执行该对象的setValue:forUndefinedKey:方法,默认是抛出异常。 ######Key取值 [self valueForKey:@"name"],与set步骤差不多。

    ####KeyPath相关 与Key方法对应,只是内部实现不一样

    - (nullable id)valueForKeyPath:(NSString *)keyPath;
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
    - (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
    - (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
    - (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
    - (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
    复制代码

    #####KeyPath设置、取值 把KeyPath分开理解

    [self setValue:@"老王" forKeyPath:@"person.name"];
    相当于
    Person *person = [self valueForKey:@"person"];
    person setValue:@"老王" forKey:@"name"];
    复制代码

    #####集合类相关

    //如果属性是一个NSMutableArray,那么可以用这个方法来返回。
    - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    
    //如果属性是一个NSMutableOrderedSet,那么可以用这个方法来返回。
    - (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
    
    //如果属性是一个NSMutableSet,那么可以用这个方法来返回。
    - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
    复制代码

    [obj mutableArrayValueForKey:@"name"];搜索过程 1、搜索insertObject:inAtIndex: , removeObjectFromAtIndex: 或者 insertAdIndexes , removeAtIndexes 格式的方法 如果至少找到一个insert方法和一个remove方法,那么同样返回一个可以响应NSMutableArray所有方法代理集合(类名是NSKeyValueFastMutableArray2),那么给这个代理集合发送NSMutableArray的方法,以insertObject:inAtIndex: , removeObjectFromAtIndex: 或者 insertAdIndexes , removeAtIndexes组合的形式调用。还有两个可选实现的接口:replaceOnjectAtIndex:withObject:,replaceAtIndexes:with:。 2、如果上步的方法没有找到,则搜索set: 格式的方法,如果找到,那么发送给代理集合的NSMutableArray最终都会调用set:方法。 也就是说,mutableArrayValueForKey:取出的代理集合修改后,用set: 重新赋值回去去。这样做效率会低很多。所以推荐实现上面的方法。 3、如果上一步的方法还还没有找到,再检查类方法+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默认行为),会按_,,的顺序搜索成员变量名,如果找到,那么发送的NSMutableArray消息方法直接交给这个成员变量处理。 4、如果还是找不到,则调用valueForUndefinedKey:。

    mutableOrderedSetValueForKey用例:

    @interface SecondViewController ()
    {
        NSMutableArray *arr;
    }
    @end
    
    @implementation SecondViewController
    
    - (void)viewDidLoad {
    
        arr = [NSMutableArray array];
        [arr addObject:@"1"];
        
        [self addObserver:self forKeyPath:@"arr" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
        
        [arr addObject:@"2"]; // 这样子操作,不触发KVO,
        
        [[self mutableArrayValueForKey:@"arr"] addObject:@"3"];// 这样子操作,触发了KVO,
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
        NSLog(@"%@",change);
    }
    复制代码

    NSDictionary相关方法

    // 输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
    - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
    
    // 字典转模型
    - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
    复制代码

    看例子就都明白了

    Address* add = [Address new];
    add.country = @"China";
    add.province = @"Guang Dong";
    add.city = @"Shen Zhen";
    add.district = @"Nan Shan";
    NSArray* arr = @[@"country",@"province",@"city",@"district"];
    NSDictionary* dict = [add dictionaryWithValuesForKeys:arr]; //把对应key所有的属性全部取出来
    NSLog(@"%@",dict);
    
    NSDictionary* modifyDict = @{@"country":@"USA",@"province":@"california",@"city":@"Los angle"};
    [add setValuesForKeysWithDictionary:modifyDict];            //用key Value来修改Model的属性
    NSLog(@"country:%@  province:%@ city:%@",add.country,add.province,add.city);
    
    //打印结果
    2016-04-19 11:54:30.846 KVCDemo[6607:198900] {
        city = "Shen Zhen";
        country = China;
        district = "Nan Shan";
        province = "Guang Dong";
    }
    2016-04-19 11:54:30.847 KVCDemo[6607:198900] country:USA  province:california city:Los angle
    复制代码

    搬运来自:iOS开发技巧系列---详解KVC(我告诉你KVC的一切) 里面还有更多用法讲解

  • 相关阅读:
    微信公众号开发:3、自定义菜单
    微信公众号开发:2、消息处理
    微信公众号开发:1、服务器配置
    基于.NetCore3.1系列 —— 日志记录之初识Serilog
    基于.NetCore3.1系列 —— 日志记录之日志核心要素揭秘
    基于.NetCore3.1系列 —— 日志记录之自定义日志组件
    基于.NetCore3.1系列 —— 日志记录之日志配置揭秘
    基于.NetCore3.1系列 —— 使用Swagger导出文档 (番外篇)
    基于.NetCore3.1系列 —— 使用Swagger导出文档 (补充篇)
    基于.NetCore3.1系列 —— 使用Swagger做Api文档 (下篇)
  • 原文地址:https://www.cnblogs.com/twodog/p/12137959.html
Copyright © 2011-2022 走看看