####NSObject(NSKeyValueCoding)
#####Key相关
//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;
//通过Key来设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
//KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//如果属性是一个NSMutableArray,那么可以用这个方法来返回。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//如果属性是一个NSMutableOrderedSet,那么可以用这个方法来返回。
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
//如果属性是一个NSMutableSet,那么可以用这个方法来返回。
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果setKey不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
// 如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;
复制代码
######Key设值
当[obj setValue:@"老王" forKey:@"name"],底层的执行机制如下:
1、程序优先调用set:属性值方法,代码通过setter方法完成设置。 2、如果没有找到setName:方法,会按照_key,_isKey,key,isKey的顺序搜索成员执行赋值;设置成NO就不这样搜索。(如果重写accessInstanceVariablesDirectly让其返回NO的话,那么在这一步KVC会执行setValue:forUndefinedKey:方法)。 3、如果上面列出的方法或者成员变量都不存在,系统将会执行该对象的setValue:forUndefinedKey:方法,默认是抛出异常。 ######Key取值 [self valueForKey:@"name"],与set步骤差不多。
####KeyPath相关 与Key方法对应,只是内部实现不一样
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
复制代码
#####KeyPath设置、取值 把KeyPath分开理解
[self setValue:@"老王" forKeyPath:@"person.name"];
相当于
Person *person = [self valueForKey:@"person"];
person setValue:@"老王" forKey:@"name"];
复制代码
#####集合类相关
//如果属性是一个NSMutableArray,那么可以用这个方法来返回。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//如果属性是一个NSMutableOrderedSet,那么可以用这个方法来返回。
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
//如果属性是一个NSMutableSet,那么可以用这个方法来返回。
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
复制代码
[obj mutableArrayValueForKey:@"name"];搜索过程 1、搜索insertObject:inAtIndex: , removeObjectFromAtIndex: 或者 insertAdIndexes , removeAtIndexes 格式的方法 如果至少找到一个insert方法和一个remove方法,那么同样返回一个可以响应NSMutableArray所有方法代理集合(类名是NSKeyValueFastMutableArray2),那么给这个代理集合发送NSMutableArray的方法,以insertObject:inAtIndex: , removeObjectFromAtIndex: 或者 insertAdIndexes , removeAtIndexes组合的形式调用。还有两个可选实现的接口:replaceOnjectAtIndex:withObject:,replaceAtIndexes:with:。 2、如果上步的方法没有找到,则搜索set: 格式的方法,如果找到,那么发送给代理集合的NSMutableArray最终都会调用set:方法。 也就是说,mutableArrayValueForKey:取出的代理集合修改后,用set: 重新赋值回去去。这样做效率会低很多。所以推荐实现上面的方法。 3、如果上一步的方法还还没有找到,再检查类方法+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默认行为),会按_,,的顺序搜索成员变量名,如果找到,那么发送的NSMutableArray消息方法直接交给这个成员变量处理。 4、如果还是找不到,则调用valueForUndefinedKey:。
mutableOrderedSetValueForKey用例:
@interface SecondViewController ()
{
NSMutableArray *arr;
}
@end
@implementation SecondViewController
- (void)viewDidLoad {
arr = [NSMutableArray array];
[arr addObject:@"1"];
[self addObserver:self forKeyPath:@"arr" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[arr addObject:@"2"]; // 这样子操作,不触发KVO,
[[self mutableArrayValueForKey:@"arr"] addObject:@"3"];// 这样子操作,触发了KVO,
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"%@",change);
}
复制代码
NSDictionary相关方法
// 输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
// 字典转模型
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
复制代码
看例子就都明白了
Address* add = [Address new];
add.country = @"China";
add.province = @"Guang Dong";
add.city = @"Shen Zhen";
add.district = @"Nan Shan";
NSArray* arr = @[@"country",@"province",@"city",@"district"];
NSDictionary* dict = [add dictionaryWithValuesForKeys:arr]; //把对应key所有的属性全部取出来
NSLog(@"%@",dict);
NSDictionary* modifyDict = @{@"country":@"USA",@"province":@"california",@"city":@"Los angle"};
[add setValuesForKeysWithDictionary:modifyDict]; //用key Value来修改Model的属性
NSLog(@"country:%@ province:%@ city:%@",add.country,add.province,add.city);
//打印结果
2016-04-19 11:54:30.846 KVCDemo[6607:198900] {
city = "Shen Zhen";
country = China;
district = "Nan Shan";
province = "Guang Dong";
}
2016-04-19 11:54:30.847 KVCDemo[6607:198900] country:USA province:california city:Los angle
复制代码
搬运来自:iOS开发技巧系列---详解KVC(我告诉你KVC的一切) 里面还有更多用法讲解