目录
- 能够对对象的私有成员进行取值赋值
- 对数值和结构体型的属性进行的打包解包处理
- 对异常处理和正确性验证
- 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
该方法的工作原理:
- 先找一下你的类中是否实现了方法 -(BOOL)validate<Key>:error:
- 如果实现了就会根据实现方法里面的自定义逻辑返回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
网友评论