KVC (Key Value Coding)知识点纪要

官方文档地址: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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。