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


上一篇下一篇

猜你喜欢

热点阅读