美文网首页OC底层相关
KVC (Key Value Coding)知识点纪要

KVC (Key Value Coding)知识点纪要

作者: bobangus | 来源:发表于2019-03-05 17:11 被阅读11次

    官方文档地址:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/BasicPrinciples.html

    目录

    • 能够对对象的私有成员进行取值赋值
    • 对数值和结构体型的属性进行的打包解包处理
    • 对异常处理和正确性验证
    • KVC与字典(可快速对对象进行设值、自定义取值等操作)
    • 消息传递
    • 容器操作 (聚合操作符 @sum 求和 @max 最大值 @min 最小值 @avg 平均值 @count 数量 注:set无序数组特点:会自动去重)
    • 集合代理对象

    一、kvc基本作用

    1、能够对对象的私有成员进行取值赋值

    2、对数值和结构体型的属性进行的打包解包处理

    Person.h

    @interface Person : NSObject{
        @private
        NSString * _sex;
        @public
        NSString * _nick;
    }
    
    @property (nonatomic ,strong) NSString *name;
    @property (nonatomic,assign) NSInteger age;
    
    @end
    

    ViewController.m

    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //1
        //访问成员变量
        Person *person = [Person new];
        person.name = @"大圣";
        NSLog(@"name = %@",person.name);
        
        //访问私有变量 需public
        person -> _nick = @"哥";
        NSLog(@"nick = %@",person ->_nick);
        
        //KVC(即使不用public修饰,也可以访问私有变量)
        [person setValue:@"男" forKey:@"_sex"];
        NSLog(@"sex = %@",[person valueForKey:@"_sex"]);
        
        //2
        //给age的是一个NSNumber对象,KVC会自动的将NSNumber对象转换成NSInteger对象,然后再调用相应的访问器方法设置age的值。
        //注意:不能直接将基本数据类型通过KVC赋值,需要把数据转成NSNumber或NSValue类型传入。
        [person setValue:[NSNumber numberWithInteger:5] forKey:@"age"];
        NSNumber *age = [person valueForKey:@"age"];
        NSLog(@"age = %@",age);
        
        
        //项目中经常用到的场景 ,更改textField字体、颜色等 几个用kvc直接设置
        [self.textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
        [self.textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];
        
    Log:
    2019-03-05 17:12:17.383171+0800 kvctest1[3120:1090729] name = 大圣
    2019-03-05 17:12:17.383314+0800 kvctest1[3120:1090729] nick = 哥
    2019-03-05 17:12:17.383499+0800 kvctest1[3120:1090729] sex = 男
    2019-03-05 17:12:17.383648+0800 kvctest1[3120:1090729] age = 5
        
        /*附:
         可以使用NSNumber的数据类型有:
         + (NSNumber*)numberWithChar:(char)value;
         + (NSNumber*)numberWithUnsignedChar:(unsignedchar)value;
         + (NSNumber*)numberWithShort:(short)value;
         + (NSNumber*)numberWithUnsignedShort:(unsignedshort)value;
         + (NSNumber*)numberWithInt:(int)value;
         + (NSNumber*)numberWithUnsignedInt:(unsignedint)value;
         + (NSNumber*)numberWithLong:(long)value;
         + (NSNumber*)numberWithUnsignedLong:(unsignedlong)value;
         + (NSNumber*)numberWithLongLong:(longlong)value;
         + (NSNumber*)numberWithUnsignedLongLong:(unsignedlonglong)value;
         + (NSNumber*)numberWithFloat:(float)value;
         + (NSNumber*)numberWithDouble:(double)value;
         + (NSNumber*)numberWithBool:(BOOL)value;
         + (NSNumber*)numberWithInteger:(NSInteger)valueNS_AVAILABLE(10_5,2_0);
         + (NSNumber*)numberWithUnsignedInteger:(NSUInteger)valueNS_AVAILABLE(10_5,2_0);
         
         可以使用NSValue的数据类型有:NSValue主要用于处理结构体型的数据,任何结构体都是可以转化成NSValue对象的,包括其它自定义的结构体。
         + (NSValue*)valueWithCGPoint:(CGPoint)point;
         + (NSValue*)valueWithCGSize:(CGSize)size;
         + (NSValue*)valueWithCGRect:(CGRect)rect;
         + (NSValue*)valueWithCGAffineTransform:(CGAffineTransform)transform;
         + (NSValue*)valueWithUIEdgeInsets:(UIEdgeInsets)insets;
         + (NSValue*)valueWithUIOffset:(UIOffset)insets;
        */
    }
    
    

    二、赋值取值过程

    赋值过程:
    1、先找相关方法  set<Key>:, _set<Key>:, setIs<Key>:
    2、若没有相关方法 + (BOOL)accessInstanceVariablesDirectly,判断是否可以直接访问成员变量
    3、如果是判断是NO,直接执行KVC的setValue:forUndefinedKey:(系统抛出一个未定义key的异常)
    4、如果是YES,继续找相关变量_<key> 􏱞_is<Key>􏱞 <key> 􏱞is<Key>
    5、方法或成员都不存在,setValue:forUndefinedKey:方法,默认是抛出异常
    
    取值过程:
    1、先找相关方法  get<Key>, key
    2、若没有相关方法 + (BOOL)accessInstanceVariablesDirectly,判断是否可以直接方法成员变量
    3、如果是判断是NO,直接执行KVC的valueForUndefinedKey:(系统抛出一个异
    常,未定义key)
    4、如果是YES,继续找相关变量_<key> _is<Key>􏱞 <key> 􏱞is<Key>
    5、方法或成员都不存在,valueForUndefinedKey:方法,默认是抛出异常
    

    三、异常处理与正确性验证

    异常处理:
    赋值为空 setNilValueForKey:
    Key值不存在 setValue:forUndefinedKey

    正确性验证:validateValue
    该方法的工作原理:

    1. 先找一下你的类中是否实现了方法 -(BOOL)validate<Key>:error:
    2. 如果实现了就会根据实现方法里面的自定义逻辑返回NO或者YES,如果没有实现这个方法,则系统默认返回就是YES

    Person.m (.h文件如上)

    //
    //  Person.m
    //  kvctest1
    //
    //  Created by mac on 2019/3/3.
    //  Copyright © 2019 mac. All rights reserved.
    //  异常处理与正确性验证
    
    #import "Person.h"
    
    @implementation Person
    
    //对非对象类型,值不能为空
    - (void) setNilValueForKey:(NSString *)key{
        NSLog(@"非对象类型key(%@)的值不能为空",key);
    }
    
    //赋值的key不存在
    - (void) setValue:(id)value forUndefinedKey:(NSString *)key{
        NSLog(@"key(%@)不存在",key);
    }
    
    //取值的key不存在
    - (id) valueForUndefinedKey:(NSString *)key{
        NSLog(@"key(%@)不存在",key);
        return nil;
    }
    
    //正确性验证
    - (BOOL) validateAge:(inout id  _Nullable __autoreleasing *)ioValue error:(out NSError * _Nullable __autoreleasing *)outError{
        NSNumber* value = (NSNumber*)*ioValue; 
        if ([value integerValue] >= 18 && [value integerValue] <= 200) {
            NSLog(@"value=%@ 符合通过条件",value);
            return YES;
        }
        return NO;
    }
    
    @end
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        Person *person = [Person new];
           //对非对象类型,值不能为空
        [person setValue:nil forKey:@"age"];
        //赋值的key不存在
        [person setValue:@"向不存在的Key设置" forKey:@"names"];
        //取值的key不存在
        [person valueForKey:@"names"];
        //正确性验证
        NSNumber* value = @200;
        if ([person validateValue:&value forKey:@"age" error:NULL]) {
            //通过验证
            [person setValue:value forKey:@"age"];
        }
    }
    
    Log:
    2019-03-05 17:15:10.427252+0800 kvctest1[3149:1105708] 非对象类型key(age)的值不能为空
    2019-03-05 17:15:10.427396+0800 kvctest1[3149:1105708] key(names)不存在
    2019-03-05 17:15:10.427538+0800 kvctest1[3149:1105708] key(names)不存在
    2019-03-05 17:15:10.427649+0800 kvctest1[3149:1105708] value=200 符合通过条件
    
    

    四、进阶

    字典用法
      //KVC与字典
    -(void)dictionaryTest{
        Person * person = [Person new];
        NSDictionary * dict = @{
                                @"name":@"齐天大圣",
                                @"nick":@"dear",
                                @"sex":@"男",
                                @"age":@18,
                                @"height":@180,
                                @"error":@"不存在的key"
                                };
        //设值
        [person setValuesForKeysWithDictionary:dict];
        NSLog(@"name = %@,age = %ld,nick = %@,height = %f",person.name,(long)person.age,person ->_nick,person.height);
        
        //取值
        NSArray * keys = @[@"name",@"age"];
        NSDictionary * tempDict = [person dictionaryWithValuesForKeys:keys];
        NSLog(@"%@",tempDict);
    }
    
    Log:
    2019-03-05 17:10:16.589987+0800 kvctest1[3089:1078915] name = 齐天大圣,age = 18,nick = dear,height = 180.000000
    2019-03-05 17:10:16.590226+0800 kvctest1[3089:1078915] {
        age = 18;
        name = "\U9f50\U5929\U5927\U5723";
    }
    
    消息传递
    //KVC的消息传递
    -(void) arrayKVCTest{
        //相当于给数组中的所有成员都发送了一遍消息
        NSArray *array =@[@"Monday",@"Tuesday",@"Wednesday"];
        NSArray *lengthArr = [array valueForKey:@"length"];
        NSArray *lowercaseStringArr = [array valueForKey:@"uppercaseString"];
        NSLog(@"长度 = %@ 转换大写 = %@",lengthArr,lowercaseStringArr);
    }
    
    Log:
    2019-03-05 17:09:37.507463+0800 kvctest1[3077:1074965] 长度 = (
        6,
        7,
        9
    ) 转换大写 = (
        MONDAY,
        TUESDAY,
        WEDNESDAY
    )
    
    容器操作
    //KVC容器操作
    -(void)containerTest{
        //聚合操作符 @sum 求和 @max 最大值 @min 最小值 @avg 平均值 @count 数量
        NSMutableArray * students = [NSMutableArray array];
        for (int i = 0; i < 6; i++) {
            Person * p = [Person new];
            NSDictionary *dict = @{
                                   @"name":@"齐天大圣",
                                   @"age":@(18 + i),
                                   @"nick":@"dear",
                                   @"height":@(1.65 + 0.02 * arc4random_uniform(6))
                                   };
            [p setValuesForKeysWithDictionary:dict];
            [students addObject:p];
        }
        NSLog(@"所有身高:%@",[students valueForKey:@"height"]);
        
        //平均身高
        float avg = [[students valueForKeyPath:@"@avg.height"] floatValue];
        NSLog(@"平均身高:%f",avg);
        
        //数组操作符 @distinctUnionOfObjects @unionOfObjects
        
        NSArray * arr = [students valueForKeyPath:@"@distinctUnionOfObjects.height"];
        NSLog(@"去重操作:%@",arr);
        
        NSArray * arr1 = [students valueForKeyPath:@"@unionOfObjects.height"];
        NSLog(@"不去重操作:%@",arr1);
        
        //嵌套集合(array&set)操作 @distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets
        NSMutableArray * students1 = [NSMutableArray array];
        for (int i=0; i< 6; i++) {
            Person * p = [Person new];
            NSDictionary *dict = @{
                                   @"name":@"齐天大圣",
                                   @"age":@(18 + i),
                                   @"nick":@"dear",
                                   @"height":@(1.65 + 0.02 * arc4random_uniform(6))
                                   };
            [p setValuesForKeysWithDictionary:dict];
            [students1 addObject:p];
        }
        
        NSArray * nestArr = @[students,students1];
        NSArray * arr2 = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.height"];
        NSLog(@"去重操作:%@",arr2);
        
        NSArray * arr3 = [nestArr valueForKeyPath:@"@unionOfArrays.height"];
        NSLog(@"不去重操作:%@",arr3);
        
        //无序集合
        //set特点:会自动去重
        NSMutableSet * studentsSet = [NSMutableSet set];
        for (int i=0; i< 6; i++) {
            Person * p = [Person new];
            NSDictionary *dict = @{
                                   @"name":@"齐天大圣",
                                   @"age":@(18 + i),
                                   @"nick":@"dear",
                                   @"height":@(1.65 + 0.02 * arc4random_uniform(6))
                                   };
            [p setValuesForKeysWithDictionary:dict];
            [studentsSet addObject:p];
        }
        NSLog(@"set自动去重 studentsSet = %@",[studentsSet valueForKey:@"height"]);
        
        NSMutableSet * studentsSet1 = [NSMutableSet set];
        for (int i=0; i< 6; i++) {
            Person * p = [Person new];
            NSDictionary *dict = @{
                                   @"name":@"齐天大圣",
                                   @"age":@(18 + i),
                                   @"nick":@"dear",
                                   @"height":@(1.65 + 0.02 * arc4random_uniform(6))
                                   };
            [p setValuesForKeysWithDictionary:dict];
            [studentsSet1 addObject:p];
        }
        NSLog(@"set自动去重 studentsSet1 = %@",[studentsSet1 valueForKey:@"height"]);
        
        NSSet * nestSet = [NSSet setWithObjects:studentsSet,studentsSet1,nil];
        
        NSArray * arrSet2 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.height"];
        NSLog(@"合并自动去重 arrSet2 = %@",arrSet2);
    }
    
    Log:
    2019-03-05 17:08:09.776498+0800 kvctest1[3052:1066595] 所有身高:(
        "1.73",
        "1.71",
        "1.67",
        "1.69",
        "1.67",
        "1.73"
    )
    2019-03-05 17:08:09.776852+0800 kvctest1[3052:1066595] 平均身高:1.700000
    2019-03-05 17:08:09.777038+0800 kvctest1[3052:1066595] 去重操作:(
        "1.69",
        "1.73",
        "1.71",
        "1.67"
    )
    2019-03-05 17:08:09.777173+0800 kvctest1[3052:1066595] 不去重操作:(
        "1.73",
        "1.71",
        "1.67",
        "1.69",
        "1.67",
        "1.73"
    )
    2019-03-05 17:08:09.777333+0800 kvctest1[3052:1066595] 去重操作:(
        "1.65",
        "1.71",
        "1.67",
        "1.73",
        "1.69"
    )
    2019-03-05 17:08:09.777460+0800 kvctest1[3052:1066595] 不去重操作:(
        "1.73",
        "1.71",
        "1.67",
        "1.69",
        "1.67",
        "1.73",
        "1.73",
        "1.65",
        "1.65",
        "1.65",
        "1.65",
        "1.69"
    )
    2019-03-05 17:08:09.777635+0800 kvctest1[3052:1066595] set自动去重 studentsSet = {(
        1.69,
        1.75,
        1.73,
        1.67,
        1.71
    )}
    2019-03-05 17:08:09.777785+0800 kvctest1[3052:1066595] set自动去重 studentsSet1 = {(
        1.65,
        1.69,
        1.75,
        1.67
    )}
    2019-03-05 17:08:09.777991+0800 kvctest1[3052:1066595] 合并自动去重 arrSet2 = {(
        1.69,
        1.75,
        1.65,
        1.73,
        1.67,
        1.71
    )}
    
    集合代理对象
    //集合代理对象
    - (void) setTest{
        Person *p = [Person new];
        p.count = 5;
         
        NSLog(@"girls = %@",[p valueForKey:@"girl"]);
        
        p.penArr = [NSMutableArray arrayWithObjects:@"pen0",@"pen1",@"pen2",@"pen3",nil];
        NSSet * set = [p valueForKey:@"pens"];
        NSLog(@"pens = %@",set);
    
        NSEnumerator * enumerator = [set objectEnumerator];
        NSString * str = nil;
        while (str = [enumerator nextObject]) {
            NSLog(@"%@",str);
        }
    }
    
    Log:
    2019-03-05 16:59:36.387904+0800 kvctest1[2947:1019754] girls = (
        girl0,
        girl1,
        girl2,
        girl3,
        girl4
    )
    2019-03-05 16:59:36.388191+0800 kvctest1[2947:1019754] pens = {(
        pen0,
        pen1,
        pen2,
        pen3
    )}
    2019-03-05 16:59:36.388296+0800 kvctest1[2947:1019754] pen0
    2019-03-05 16:59:36.388395+0800 kvctest1[2947:1019754] pen1
    2019-03-05 16:59:36.388474+0800 kvctest1[2947:1019754] pen2
    2019-03-05 16:59:36.388582+0800 kvctest1[2947:1019754] pen3
    

    相关文章

      网友评论

        本文标题:KVC (Key Value Coding)知识点纪要

        本文链接:https://www.haomeiwen.com/subject/tvaeuqtx.html