- (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值
+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回
- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一个方法一样,只不过是设值。
- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
使用方法:
Dog* dog = [Dog new];
dog.name = @"KeLe";
[people setValue:dog forKey:@"myDog"];//myDog为People类的属性 @property (nonatomic, strong) Dog *myDog;
NSString* name1 = people.myDog.name;
NSString * name2 = [people valueForKeyPath:@"myDog.name"];//people类的myDog成员也属于自定义类。要获取到myDog中的name属性。1.可以先valueForKey获取到myDog,再通过valueForKey获取到name。但是这样太麻烦了。我们直接用keyPath直接获取成员变量(自定义类)的属性。
NSLog(@"name1:%@ name2:%@",name1,name2);
//打印结果
2018-03-30 11:20:10.129 KVCDemo[1346:95910] name1:KeLe name2:KeLe
什么时候用?
1.需要获取类的私有属性。比如如何修改textField的placeholder的颜色和字体大小呢?MyTextField setValue: forKeyPath:(_placeHolderLabel.textColor _placeHolderLabel.font)。如果你问我为什么知道UITextField的占位Label的名字是_placeHoldLabel。教你一招:
- (NSMutableArray *)getAllIvarListInClass:(Class)iVarClass {
unsigned int numIvars; //成员变量个数
NSMutableArray *allIvar = [NSMutableArray array];
Ivar *vars = class_copyIvarList(iVarClass, &numIvars);
NSString *key=nil;
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = vars[i];
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)]; //获取成员变量的名字
NSLog(@"variable name :%@", key);
[allIvar addObject:key];
key = [NSString stringWithUTF8String:ivar_getTypeEncoding(thisIvar)]; //获取成员变量的数据类型
NSLog(@"variable type :%@", key);
}
free(vars);
return allIvar;
}
返回当前类的所有成员变量。之后 我们可以通过变量名判断是哪个属性类型。
2.动态取值,设置。如上代码所示。
3.操作集合,NSArray,NSSet。
4.将字典转化为model
NSDictionary *dict = @{
@"name" : @"zhangsan",
@"height" : @"175",
};
// 创建模型
Person *p = [[Person alloc] init];
// 字典转模型
[p setValuesForKeysWithDictionary:dict];
NSLog(@"person's name is the %@",p.name);
比较常用的场景大概就是这些
name为myKVC类中的属性。
[myKVC addObserver:self forKeyPath:@"name" options: NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//拿到新值/旧值,进行操作
NSLog(@"newValue----%@",change[@"new"]);
NSLog(@"oldValue----%@",change[@"old"]);
}
取消监听:
-(void)dealloc
{
[myKVC removeObserver:self forKeyPath:@"name"];
}
什么时候用呢?
1.监听模型属性,更新UI,比如列表有个阅读数,点击进入详情,阅读数应该+1,返回列表则应该通过对应的UI表现出来。
2.监听上拉刷新,下拉加载的contentoffesize。
3.室内地图,蓝牙开发中,监听当前点的postion。实时更新UI。
4.webview混排监听contentsize。