KVC学习笔记

NSObject有个扩展NSKeyValueCoding,所以所有的oc都都可以基于kvc进行属性的访问。先看一下kvc的各种操作方法的使用示例。

基本赋值操作

对于普通对象通过valueForKey:setValue:forKey:进行读取。

LGPerson *person = [[LGPerson alloc] init];
    // 一般setter 方法
    person.name      = @"LG_Cooci"; // setter -- llvm
    person.age       = 18;
    person->myName   = @"cooci";
    NSLog(@"%@ - %d - %@",person.name,person.age,person->myName);
   
    // 1:Key-Value Coding (KVC) : 基本类型 - 看底层原理
    // 非正式协议 - 间接访问
    [person setValue:@"KC" forKey:@"name"];
    
    // 2:KVC - 集合类型
    person.array = @[@"1",@"2",@"3"];
    // 修改数组
    // person.array[0] = @"100";
    // 第一种:搞一个新的数组 - KVC 赋值就OK
    NSArray *array = [person valueForKey:@"array"];
    array = @[@"100",@"2",@"3"];
    [person setValue:array forKey:@"array"];
    NSLog(@"%@",[person valueForKey:@"array"]);
    // 第二种
    NSMutableArray *mArray = [person mutableArrayValueForKey:@"array"];
    mArray[0] = @"200";
    NSLog(@"%@",[person valueForKey:@"array"]);

字典操作

把字典中的key和对象的属性一一对应起来

- (void)dictionaryTest{
    
    NSDictionary* dict = @{
                           @"name":@"Cooci",
                           @"nick":@"KC",
                           @"subject":@"iOS",
                           @"age":@18,
                           @"length":@180
                           };
    LGStudent *p = [[LGStudent alloc] init];
    // 字典转模型
    [p setValuesForKeysWithDictionary:dict];
    NSLog(@"%@",p);
    // 键数组转模型到字典
    NSArray *array = @[@"name",@"age"];
    NSDictionary *dic = [p dictionaryWithValuesForKeys:array];
    NSLog(@"%@",dic);
}

消息传递

对数组中每个对象发送消息,相当于遍历数据并调用相应方法

- (void)arrayMessagePass{
    NSArray *array = @[@"Hank",@"Cooci",@"Kody",@"CC"];
    NSArray *lenStr= [array valueForKeyPath:@"length"];
    NSLog(@"%@",lenStr);// 消息从array传递给了string
    NSArray *lowStr= [array valueForKeyPath:@"lowercaseString"];
    NSLog(@"%@",lowStr);
}

聚合操作符

相当于遍历数组中的每个对象,取其对应字段组装成一个新的数组,然后针对该数组进行进一步的聚合处理,avg、count、sum等

- (void)aggregationOperator{
    NSMutableArray *personArray = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        LGStudent *p = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [p setValuesForKeysWithDictionary:dict];
        [personArray addObject:p];
    }
    NSLog(@"%@", [personArray valueForKey:@"length"]);
    
    /// 平均身高
    float avg = [[personArray valueForKeyPath:@"@avg.length"] floatValue];
    NSLog(@"%f", avg);
    
    int count = [[personArray valueForKeyPath:@"@count.length"] intValue];
    NSLog(@"%d", count);
    
    int sum = [[personArray valueForKeyPath:@"@sum.length"] intValue];
    NSLog(@"%d", sum);
    
    int max = [[personArray valueForKeyPath:@"@max.length"] intValue];
    NSLog(@"%d", max);
    
    int min = [[personArray valueForKeyPath:@"@min.length"] intValue];
    NSLog(@"%d", min);
}

数组操作符

相当于遍历数据中的元素,取其对应的字段组成新数组后,进行unionOfObjects、distinctUnionOfObjects操作

- (void)arrayOperator{
    NSMutableArray *personArray = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        LGStudent *p = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [p setValuesForKeysWithDictionary:dict];
        [personArray addObject:p];
    }
    NSLog(@"%@", [personArray valueForKey:@"length"]);
    // 返回操作对象指定属性的集合
    NSArray* arr1 = [personArray valueForKeyPath:@"@unionOfObjects.length"];
    NSLog(@"arr1 = %@", arr1);
    // 返回操作对象指定属性的集合 -- 去重
    NSArray* arr2 = [personArray valueForKeyPath:@"@distinctUnionOfObjects.length"];
    NSLog(@"arr2 = %@", arr2);
    
}

嵌套集合(array&set)操作

相当于把嵌套的集合平铺开来当成一个集合后再进行操作

- (void)arrayNesting{
    
    NSMutableArray *personArray1 = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        LGStudent *student = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [personArray1 addObject:student];
    }
    
    NSMutableArray *personArray2 = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        LGStudent *person = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [person setValuesForKeysWithDictionary:dict];
        [personArray2 addObject:person];
    }
    
    // 嵌套数组
    NSArray* nestArr = @[personArray1, personArray2];
    
    NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.length"];
    NSLog(@"arr = %@", arr);
    
    NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.length"];
    NSLog(@"arr1 = %@", arr1);
}

- (void)setNesting{
    
    NSMutableSet *personSet1 = [NSMutableSet set];
    for (int i = 0; i < 6; i++) {
        LGStudent *person = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [person setValuesForKeysWithDictionary:dict];
        [personSet1 addObject:person];
    }
    NSLog(@"personSet1 = %@", [personSet1 valueForKey:@"length"]);
    
    NSMutableSet *personSet2 = [NSMutableSet set];
    for (int i = 0; i < 6; i++) {
        LGStudent *person = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [person setValuesForKeysWithDictionary:dict];
        [personSet2 addObject:person];
    }
    NSLog(@"personSet2 = %@", [personSet2 valueForKey:@"length"]);

    // 嵌套set
    NSSet* nestSet = [NSSet setWithObjects:personSet1, personSet2, nil];
    // 交集
    NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.length"];
    NSLog(@"arr1 = %@", arr1);
}

setValue:forKey:流程梳理

在我们调用[person setValue:@"xxx" forKey:@"name"]这行代码时,oc底层将经过以下几个步骤:

  1. 依次调用name的几个set方法,setName、_setName、setIsName,如果都没有进入步骤2
  2. 根据accessInstanceVariablesDirectly方法返回值判断是否需要进行实例变量转发流程,如果是则会依次对_name、_isName、name、isName进行赋值,如果否则进行步骤3
  3. 调用setValue:forUnderfineKey:方法,在这里开发者可以进行最后一次补救,否则就会崩溃

valueForKey流程梳理

在我们调用[person valueForKey:@"name"]这行代码时,oc底层将经过以下几个步骤:

  1. 依次调用name的几个get方法,getName、name、isName、_name,如果都没有进入步骤2
  2. 此时先判断是否集合类型,会判断是否有countOf、memberOf等方法,如果有则表示集合类型并进行方法调用后组装成对应类型的集合并返回,如果没有则进入步骤3
  3. 根据accessInstanceVariablesDirectly方法返回值判断是否需要进行实例变量转发流程,如果是则会依次尝试取_name、_isName、name、isName字段,如果否进入步骤4
  4. 调用valueForUndefinedKey:方法,在这里开发者可以进行最后一次补救,否则就会崩溃

推荐学习
https://github.com/renjinkui2719/DIS_KVC_KVO

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在编程中,最常见的就是程序的流程取决于你所使用的各种变量和属性的值,根据变量和属性的值确定后面运行的代码,有时会检...
    pro648阅读 5,570评论 2 27
  • KVC官方介绍:查看文档 成员变量、实例变量及属性的区别 如图一,大括号里边的都是成员变量,而实例变量是特殊的成员...
    好久不见_47b7阅读 3,764评论 0 0
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    我的梦工厂阅读 4,340评论 1 8
  • 本文为L_Ares个人写作,以任何形式转载请表明原文出处。 资料准备 : AppleDevelopment - K...
    L_Ares阅读 1,449评论 0 2
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    朽木自雕也阅读 5,476评论 6 1