KVC
2019-04-16 本文已影响0人
英雄出少年
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
setValue:forKey:方法, 只能给对象的直接属性赋值
setValue:forKeyPath: 可以给对象的间接属性赋值. 多层赋值
赋值、获取单个值
赋值:
[p setValue:@"zit" forKey:@"name"];
取值:
NSString *name = [p valueForKey:@"name"];
赋值、获取多层值
赋值:
[p setValue:@"xiaoqiang" forKeyPath:@"dog.name"];
取值:
NSString *dogName = [p valueForKeyPath:@"dog.name"];
给私有成员变量赋值
[p setValue:@"lnj" forKey:@"_name"];
字典转模型和模型转字典
字典转模型:
[p setValuesForKeysWithDictionary:dict];
模型转字典:
NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name", @"money"];
获取数组中对象的值
如果数组中的元素都是同一种类型的数据, 可以使用KVC获取数组中所有对象的某个属性的值
NSArray *res = [arr valueForKeyPath:@"name"];
运算符
id res1 = [arr valueForKeyPath:@"@avg.money"];
// KVC的作用
// 1.可以访问私有成员变量的值
// 2.可以间接修改私有成员变量的值(替换系统自带的导航栏、tabbar)
TGPerson *p = [[TGPerson alloc] init];
p.age = 20;
NSLog(@"年龄=%d", p.age);
NSLog(@"年龄=%d", [p age]);
NSLog(@"%f", [[p valueForKey:@"_height"] floatValue]);//默认做法先访问get方法 ,在访问成员变量
float h1 = [[p valueForKey:@"height"] floatValue];
float h2 = [[p valueForKeyPath:@"height"] floatValue];
NSLog(@"%f %f", h1, h2);
p.dog = [[HMDog alloc] init];
p.dog.name = @"wangcai";
NSLog(@"%@", [p valueForKeyPath:@"dog.name"]);
// keyPath包含了key的功能
// key:只能访问当前对象的属性
// keyPath:能利用.运算符一层一层往内部访问属性
3. 统计
TGBook *b1 = [[TGBook alloc] init];
b1.name = @"kuihua";
b1.price = 100.6;
HMBook *b2 = [[HMBook alloc] init];
b2.name = @"pixie";
b2.price = 5.6;
HMBook *b3 = [[HMBook alloc] init];
b3.name = @"jiuyin";
b3.price = 50.6;
p.books = @[b1, b2, b3];
NSLog(@"%@", [p valueForKeyPath:@"books.@count"]); // 计算数组的长度
NSArray *names = [p valueForKeyPath:@"books.name"];
NSArray *names = [p.books valueForKeyPath:@"name"];
NSLog(@"%@", names);
求和
double sumPrice = [[p valueForKeyPath:@"books.@sum.price"] doubleValue];
NSLog(@"%f", sumPrice);
通过KVC修改属性会触发KVO么?
@interface TGPerson : NSObject
@property (assign, nonatomic) int age;
@end
@implementation TGPerson
@end
@interface TGObserver : NSObject
@end
@implementation TGObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"observeValueForKeyPath - %@", change);
}
@end
/** 打印结果
observeValueForKeyPath - {
kind = 1;
new = 10;
old = 0;
*/
int main(int argc, const char * argv[]) {
@autoreleasepool {
TGObserver *observer = [[TGObserver alloc] init];
TGPerson *person = [[TGPerson alloc] init];
// 添加KVO监听
[person addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
// 通过KVC修改age属性
[person setValue:@10 forKey:@"age"];
// 移除KVO监听
[person removeObserver:observer forKeyPath:@"age"];
}
return 0;
}
setValue:forKey:的原理
setValue:forKey原理.png通过kvc修改成员变量也会触发kvo监听,不需要调用属性set方法
//kvc修改成员变量内部实现
[person willChangeValueForKey:@"age"];
person->_age = 10;
[person didChangeValueForKey:@"age"];
valueForKey:的原理
valueForKey原理.png@interface TGPerson : NSObject
{
@public
int age;
// int isAge;
// int _isAge;
// int _age;
}
@end
@implementation TGPerson
//- (int)getAge
//{
// return 11;
//}
//- (int)age
//{
// return 12;
//}
//- (int)isAge
//{
// return 13;
//}
//- (int)_age
//{
// return 14;
//}
//- (void)setAge:(int)age
//{
// NSLog(@"setAge: - %d", age);
//}
//- (void)_setAge:(int)age
//{
// NSLog(@"_setAge: - %d", age);
//}
- (void)willChangeValueForKey:(NSString *)key
{
[super willChangeValueForKey:key];
NSLog(@"willChangeValueForKey - %@", key);
}
- (void)didChangeValueForKey:(NSString *)key
{
NSLog(@"didChangeValueForKey - begin - %@", key);
[super didChangeValueForKey:key];
NSLog(@"didChangeValueForKey - end - %@", key);
}
// 默认的返回值就是YES
//+ (BOOL)accessInstanceVariablesDirectly
//{
// return YES;
//}
@end