深入探索KVC

来源:互联网 发布:淘宝网天猫全棉女卫衣 编辑:程序博客网 时间:2024/06/11 16:31

顺便解释一下KVO和KVC

在学习完iOS时,或许我们经常对KVO和KVC产生迷惑,不能够非常清楚的区分KVC与KVO之间的关系,此处声明二者使用时没有直接的联系。小编简单做一下区别:

KVO key-value-observe是一种设计模式,它观察对象的某一个属性的变化KVC key-value-coding 是一种间接访问对象成员属性的的方法,可以通过该方法间接修改或获取对象的属性值 二者主要区别:KVO侧重观察值得变化,KVC侧重对数据的读取

下面重点介绍KVC

  • 为了更加清楚解释我先创建了两个类
// BGWork#import <Foundation/Foundation.h>@class BGCompany;@interface BGWorker : NSObject{    NSString *name;    NSInteger age;    NSString *gender;    BGCompany *company;    NSArray *fellows;     @private    NSString *address;}@property (nonatomic, readonly, copy) NSString *number;@end#import "BGWorker.h"@implementation BGWorker@end// BGCompany#import <Foundation/Foundation.h>@interface BGCompany : NSObject{    NSString *companyName;    NSString *ID;}@end#import "BGCompany.h"@implementation BGCompany@end
  • 最简单的KVC,直接调用方法赋值
/* - (void)setValue:(nullable id)value forKey:(NSString *)key; */        BGWorker *worker = [[BGWorker alloc]init];        // 赋值操作        [worker setValue:@"zhangsan" forKey:@"name"];        [worker setValue:@12 forKey:@"age"];        [worker setValue:@"男" forKey:@"gender"];        // 取值操作        NSString *name = [worker valueForKey:@"name"];        NSNumber *age = [worker valueForKey:@"age"];        NSString *gender = [worker valueForKey:@"gender"];        NSLog(@"name = %@ age = %@ gender = %@", name, age, gender);
  • 复杂对象作为成员变量,对复杂对象成员变量赋值
    此时需要用到另一个方法,关联keyPath
        /* - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; */        BGCompany *company = [[BGCompany alloc]init];        // 复杂对象赋值        [worker setValue:company forKey:@"company"];        // 根据路径赋值        [worker setValue:@"leliankeji" forKeyPath:@"company.companyName"];        [worker setValue:@"213432423" forKeyPath:@"company.ID"];        // 根据路径取值        NSString *companyName = [worker valueForKeyPath:@"company.companyName"];        NSString *ID = [worker valueForKeyPath:@"company.ID"];        NSLog(@"company:%@ - %@", companyName, ID);
  • KVC的高级用法,如果对象内的数组中存放的也是同一类型的某种复杂对象,则可以对该对象的某一属性执行一定操作。比如,求和,计数,最大值,最小值
        BGWorker *work1 = [[BGWorker alloc]init];        [work1 setValue:@"13" forKeyPath:@"age"];        BGWorker *work2 = [[BGWorker alloc]init];        [work2 setValue:@"14" forKeyPath:@"age"];        BGWorker *work3 = [[BGWorker alloc]init];        [work3 setValue:@"15" forKeyPath:@"age"];        NSArray *arr = [NSArray arrayWithObjects:work1, work2, work3, nil];        [worker setValue:arr forKeyPath:@"fellows"];        NSLog(@"%@", [worker valueForKey:@"fellows"]);        NSLog(@"%@", [worker valueForKeyPath:@"fellows.age"]); // 获取数组内每个对象的age        NSLog(@"%@", [worker valueForKeyPath:@"fellows.@count.age"]); // 数组含有年龄属性的元素个数        NSLog(@"%@", [worker valueForKeyPath:@"fellows.@sum.age"]); // 数组内所有元素age的和        NSLog(@"%@", [worker valueForKeyPath:@"fellows.@avg.age"]); // 平均值        NSLog(@"%@", [worker valueForKeyPath:@"fellows.@min.age"]); // 最小值        NSLog(@"%@", [worker valueForKeyPath:@"fellows.@max.age"]); // 最大值
  • 另一种KVC,对对象整体赋值
/* - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues; */     NSDictionary *dic = @{@"name": @"lisi",                              @"age" : @"21",                              @"gender" :@"男",                              @"fellows" :@[work1, work2, work3],                              @"company" :company };        BGWorker *worker2 = [[BGWorker alloc]init];        [worker2 setValuesForKeysWithDictionary:dic];        NSLog(@"%@", [worker2 valueForKey:@"name"]);        NSLog(@"%@", [worker2 valueForKey:@"age"]);        NSLog(@"%@", [worker2 valueForKey:@"gender"]);        NSLog(@"%@", [worker2 valueForKey:@"fellows"]);        NSLog(@"%@", [worker2 valueForKeyPath:@"company.companyName"]);        NSLog(@"%@", [worker2 valueForKeyPath:@"company.ID"]);

发现

  1. 如果成员变量是自定义对象,还会触发成员变量的setValuesForKeyWithDictionary:方法,该对象的各个成员变量也会被赋值。
  2. 如果一个类不去写成属性,也不实现getter setter 方法我们依然可以通过KVC访问他的成员属性,
  3. 通过KVC我们还可以访问私有属性(呵呵,绝对独家),此处证明私有属性不提供外部接口依然可以读写(前提必须知道成员变量名,即key)
        [worker setValue:@"北京" forKey:@"address"];        NSLog(@"##%@##", [worker valueForKey:@"address"]);


4. readOnly 可以使用KVC赋值(这也是独家哦)

            // 只读重置值        [worker setValue:@"13260318431" forKey:@"number"];        NSLog(@"%@", [worker valueForKey:@"number"]);

源码地址

0 0
原创粉丝点击