KVC是一种间接传值的方法,利于对象之间的解耦,让对象直接的耦合性不要太高
//kev对对象赋值或者取值时,需要知道准确的键值
//相比较点语法,kvc是一种间接的传递方式,这种方式有利于对象解偶,让对象直接的耦合性不要太高
setValue:forKey 给对象当前的属性赋值
setValue:<#(nullable id)#> forKeyPath:<#(nonnull NSString *)#> 按照对象的层次关系为其中的属性赋值
//forKeyPath 可以替代forKey,但是forkey不能替换forkeypath
// 我们一般通过调用set方法或属性的点语法来直接更改对象的状态,即对象的属性 kvc是一种简洁更改对象状态的方式,其使用方法是使用描叙对象需要更改的属性。kvc中的基本调用包括valueForKey 和 setValue:ForKey以字符串的形式向对象发送消息使用下面的例子
//@interface Card : NSObject
//@property (nonatomic,assign) int no;
//@end
//
//@interface Student : NSObject
//
//@property (nonatomic,assign) int age;
//
//@property (nonatomic,copy) NSString *name;
//
//@property (nonatomic,retain) Card *card;
//
//@end
//valueForKey:获取Student对象的name
//NSString *name = [student valueForKey:@"name"];
//valueForKey:首先查找以name或isName命名的getter方法,如果不存在getter方法,就在对象内部查找名为_name或name的实例变量
//下面的语法是合法的
// NSLog(@"age is %@ ",[Student valueForKey:@"age"]);
// NSLog中的%@输出一个对象但age是一个int值而不是一个对象 为什么会合理呢
// 因为在使用valueForKey时 kvc会自动将标量值(int,float。struct)等翻入NSNumber或NSValue中包装成对象,因此valueforkey具有自动包装功能
// 使用setValue:ForKey:设置Student对象的name
// [student setValue:@"MJ" forKey:@"name"];
// 这个方法的工作方式和valueForKey:相同,首先查找setter方法,例如setName:,如果不存在setter方法,就在类中查找名为name或者_name的实例变量,然后为它赋值
//
// 使用setValue:ForKey:设置Student对象的age
// [student setValue:[NSNumber numberWithInt:17] forKey:@"age"];
// 使用kvc在设置一个标量时,需要先将标量值包装成一个NSNumber或NSvalue对象
// kvc 可以对对象进行批量更改
// 同时获取Student的age和name
// NSArray *keys = [NSArray arrayWithObjects:@"name",@"age",nil];
// NSDictionary *dict = [student dictionaryWithValuesForKeys:keys];
// 同时设置Student的age和name
// NSArray *keys = [NSArray arrayWithObjects:@"name", @"age", nil];
// NSArray *values = [NSArray arrayWithObjects:@"MJ", [NSNumber numberWithInt:16], nil];
// NSDictionary *dict = [NSDictionary dictionaryWithObjects:values forKeys:keys];
// [student setValuesForKeysWithDictionary:dict];
//除了通过键设置值外,kvc还支持键路径像文件系统路径一样,其实就是属性链式访问
//比如 利用键路径设置Student对象中的card对象的no
// [student setValue:@"12345" forKeyPath:@"card.no"];
// [student valueForKeyPath:@"card.no"];
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView
//如果向一个NSarray请求一个key,KVC会查询数组中的每个对象来查找这个key然后将查询结果打包到另一个数组中并返回
// 获取Student中所有Book的name
// NSArray *names = [student.books valueForKeyPath:@"name"]; 或者
// NSArray *names = [student valueForKeyPath:@"books.name"];
// 注意:不能在键路径中为数组添加索引,比如@"books[0].name"
//键路径运算符
//在键路径中,可以引用一些运算符来进行一些运算,例如可以获取一组值的平均值 ,最小值,最大值或者总数
//例如计算Student中的所有book的价钱(price)总和
// NSNumber *count = [student.books valueFOrKEyPath:@"@count"];
// NSNumber *count = [student valueFOrKEyPath:@"books.@count"];
//计算Studengt中所有Book的价钱(price)总和
// NSNumber *sum = [student.books valueFOrKEyPath:@"@count"];
//
// NSNumber *sum = [student valueFOrKEyPath:@"books.@count"];
// 找出Student中的book的所有不同价位÷
// NSArray *prices = [student.books valueFOrKeyPath:@"distinctUnionOfObjects.price"];
//
// NSArray *prices = [student valueForKeyPath:@"books.@distinctUnionOfObjects.price"];
// KVO(key value observing)
// kvo 是一种非常重要的机制,它允许监听对象的属性的变化
// -(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
// anObserver :监听器对象
// keyPath :监听的属性
// options :决定了当属性改变时,要传递什么数据给监听器
// 监听器需要实现监听方法
// -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
//change:(NSDictionary *)change context:(void *)context
// keyPath :监听的属性
// object :谁的属性改变了
// change :属性改变时传递过来的信息(取决于添加监听器时的options参数)
// 监听器需要实现监听方法
// -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
//change:(NSDictionary *)change context:(void *)context
// keyPath :监听的属性
// object :谁的属性改变了
// change :属性改变时传递过来的信息(取决于添加监听器时的options参数)
//
// 移除监听器
// -(void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
}