_person = [[Person alloc] init];
/**
* 添加观察者
*
* @param observer 观察者
* @param keyPath 被观察的属性名称
* @param options 观察属性的新值、旧值等的一些配置(枚举值,能够根据须要设置,例如这里可使用两项)
* @param context 上下文,能够为nil。
*/
[_person addObserver:self
forKeyPath:@"age"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
/**
* KVO 回调方法
*
* @param keyPath 被修改的属性
* @param object 被修改的属性所属对象
* @param change 属性改变状况(新旧值)
* @param context context 传过来的值
*/
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context
{
NSLog(@"%@ 对象的%@属性改变了:%@",object,keyPath,change);
}
/**
* 移除观察者
*/
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"age"];
}
复制代码
[scrollview addObserver:self
forKeyPath:@“contentOffset
options:NSKeyValueObservingOptionNew
context:nil];
复制代码
【注册】1.// 注册观察者,实施监听;
[self.person addObserver:self
forKeyPath:@"age"
options:NSKeyValueObservingOptionNew
context:nil];
【观察】2.// 观察方法,回调方法,在这里处理属性发生的变化;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context
【移除】3.// 移除观察者;
[self removeObserver:self forKeyPath:@“age"];
复制代码
KVC 缺点数组
NSArray *a = @[@4, @84, @2];
NSLog(@"max = %@", [a valueForKeyPath:@"@max.self"]);
复制代码
NSArray *a = @[transaction1, transaction2, transaction3];
NSLog(@"max = %@", [a valueForKeyPath:@"@max.amount"]);
复制代码
@interface Teacher : NSObject
{
@private int _age;// 私有变量,通常外部不能改变,经过kvc能够改变,前提你知道这个私有变量的名字;
}
@property (nonatomic, strong, readonly) NSString *name;// 只读变量,一个外部不能直接赋值,经过kvc能够改变
@property (nonatomic, assign, getter = isMale) BOOL male;
- (void)log;
@end
复制代码
Teacher *teacher = [Teacher new];
[teacher log];
// 设置 readonly value
[teacher setValue:@"Jack" forKey:@"name"];
// teacher.name = @"Jack";
// 设置 private value
[teacher setValue:@24 forKey:@"age"];
// teacher.age = 24;
[teacher setValue:@1 forKey:@"male"];
[teacher log];
// 获取 readonly value
NSLog(@"name: %@", [teacher valueForKey:@"_name"]);
// 获取 private value
NSLog(@"age: %d", [[teacher valueForKey:@"_age"] intValue]);
NSLog(@"male: %d", [[teacher valueForKey:@"isMale"] boolValue]);
复制代码
[_textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[_textField setValue:[UIFont systemFontOfSize:14] forKeyPath:@“_placeholderLabel.font"];
复制代码
[_pageControl setValue:[UIImage imageNamed:@"selected"] forKeyPath:@"_currentPageImage"];
[_pageControl setValue:[UIImage imageNamed:@"unselected"] forKeyPath:@"_pageImage"];
复制代码
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
复制代码
key 和keypath的区别?markdown
key只能接受当前类所具备的属性,无论是本身的,仍是从父类继承过来的,如view.setValue(CGRectZero(),key: "frame");函数
keypath: 除了能接受当前类的属性,还能接受当前类属性的属性,便可以接受关系链,如view.setValue(5,keypath: "layer.cornerRadius”)编码
举个例子说明问题1:atom
例子:好比person有个属性是address,address有个属性是town,如今咱们如何经过person访问town属性?spa
答:若是经过key来访问指针
id address = [person valueForKey:@"address"];
id town = [address valueForKey:@"town”];
// 若是经过keypath来访问
id town = [person valueForKeyPath:@"address.town"];
复制代码
// value 的值为OC对象,若是是基本数据类型要包装成NSNumber
- (void)setValue:(id)value forKey:(NSString *)key;
// keyPath 键路径,类型为xx.xx
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
// 它的默认实现是抛出异常,能够重写这个函数作错误处理。
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
复制代码
- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
// 若是Key不存在,且没有KVC没法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
- (id)valueForUndefinedKey:(NSString *)key;
复制代码
// 容许直接访问实例变量,默认返回YES。若是某个类重写了这个方法,且返回NO,则KVC不能够访问该类。
+ (BOOL)accessInstanceVariablesDirectly;
// 这是集合操做的API,里面还有一系列这样的API,若是属性是一个NSMutableArray,那么能够用这个方法来返回
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
// 若是你在setValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;
// 输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
// KVC 提供属性值确认的API,它能够用来检查set的值是否正确、为不正确的值作一个替换值或者拒绝设置新值并返回错误缘由。
- (BOOL)validateValue:(id)ioValue forKey:(NSString *)inKey error:(NSError)outError;
复制代码