文章目录
1.KVC
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (nullable id)valueForKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- 可以访问私有的成员变量和属性
2. setValue:forKey: 的原理
- KVC的赋值过程 :
- 先找到相关方法
set, _set : 按顺序,如果前面的方法都没有找到,执行后续方法- +(BOOL)accessInstanceVariableDirectly:
判断是否可以直接赋值,默认返回值时YES
如果返回值是NO : 直接抛出一个异常 setValue:forUndefinedKey:
如果返回值是YES : 继续查找成员变量- 查找成员变量
_Key ,_isKey ,Key ,isKey ,找到这些成员变量,然后赋值.- 方法或者成员变量都找不到,默认抛出异常
.h
NSString *_name;//1
NSString *_isName;//2
NSString *name;//3
NSString *isName;//4
.m
[p setValue:@"yuanhao" forKey:@"name"];;
NSLog(@"name = %@",p->_name);//1.1 _key
NSLog(@"_name = %@",p->_isName);//2.1 _iskey
NSLog(@"isName = %@",p->name);//3.1 key
NSLog(@"_isName = %@",p->isName);//4.1 iskey
/*
如果没有都没有注释,1.1有值
注释了1 , 2.1打印值,其它都为null
注释了1,2 , 3.1打印值,其它为null
...
给key name赋值,按步骤4的顺序,先给_name赋值,如果没有_name的变量,再给_isName赋值.....
*/
3. valueForKey: 的原理
- 取值过程
- 先找到相关方法
get,,is,<_Key>- 如果没有找到相关方法
+(BOOL)accessInstanceVariableDirctly:
如果返回值是NO , 直接抛出一个异常,valueForUndefinedKey:
如果返回值是YES- 继续查找成员变量
_key ,_isKey ,key ,isKey ,找到这些成员变量直接取值- 方法或者成员变量都不存在,抛出异常
4. KVC进阶用法
1. KVC异常处理,正确性验证
- 可以复写这些方法来捕获错误
-(void)setNilValueForKey:(NSString *)key{}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{}
-(id)valueForUndefinedKey:(NSString *)key
2.KVC与字典
- setValueForKeysWithDictionary: //字典转模型
[self dictionaryWithValuesForKeys:<#(nonnull NSArray<NSString *> *)#>] //
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys; //模型转字典
3.KVC消息传递
给数组的每个成员变量发送消息
- (void)arrayKVCTest{
NSArray *arr =@[@"monday",@"yuanhao",@"fengfeng"];
NSArray *lengthArr = [arr valueForKey:@"length"];
NSLog(@"%@",lengthArr);
(
6,
7,
8
)
4. KVC容器操作
- 聚合操作符 @avg,@count,@max,@min,@sum
- 数组操作符
- 嵌套集合(array&set)操作
- 聚合操作
p1.height = 1.65
p2.height = 1.55
arr addObject:p
[arr valueForKey:@"height"]; //获取所有的成员的高度
//平均身高
[[arr valueForKey:@"@avg.height"] floatValue]
- 数组操作符
[arr valueForKey:@"@distindtUnionOfObjects.height"] //去重
- 嵌套集合(array&set)操作
类似2.
5.面试题
1.通过KVC修改属性会触发KVO么?
会触发KVO
self->_age = @"3333"; //直接给成员变量赋值不会触发KVO
_age = @"123"; // 直接修改成员变量不会触发KVO
[self setValue:@"1234" forKey:@"_age"];//不会触发KVO age是属性 修改属性的成员变量不会触发KVO
[self setValue:@"1234" forKey:@"age"];//会触发KVO 直接修改属性会触发KVO
_height = 100; // 不会触发KVO 直接修改成员变量不会触发KVO
/*
[self addObserver:self forKeyPath:@"_height" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:@"self-_hright"];
如果直接观察成员变量,KVC能够触发
*/
[self setValue:@123 forKey:@"_height"];//使用KVC修改成员变量会触发KVO