KVC与KVO

KVC与KVO

一:KVC(自定义一个Person类和Dog类,Persor类拥有name,money,和Dog对象属性,Dog拥有name和price属性)

1.通过KVC获取值

  • 获取单个词

    Person *p = [Person new];
    p.name = @"lmj";
    p.money = 998;
    p.dog = [Dog new];
    p.dog.name = @"wangcai";
    p.dog.price = 110;
    NSLog(@"%@ , %f", p.name, p.money);

    NSString *name =  [p valueForKey:@"name"];
    NSLog(@"name = %@", name);
    double money = [[p valueForKey:@"money"] doubleValue];
    NSLog(@"money = %f", money);
  • 获取多层词

    • 获取间接属性

//    NSString *dogName = [p valueForKey:@"dog.name"];
//    NSString *dogName = [p valueForKeyPath:@"dog.name"];
//    NSLog(@"dogName = %@", dogName);
  • 模型转字典

//    NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name", @"money"]];
//    NSLog(@"%@", dict);
  • 获取数组中对象的值

    Person *p1 = [Person new];
    p1.name = @"zs";
    p1.money = 111;

    Person *p2 = [Person new];
    p2.name = @"ls";
    p2.money = 222;

    Person *p3 = [Person new];
    p3.name = @"ww";
    p3.money = 666;

    NSArray *arr = @[p1, p2, p3];

    // 如果数组中的元素都是同一种类型的数据, 可以使用KVC获取数组中所有对象的某个属性的值
    NSArray *res = [arr valueForKeyPath:@"name"];
    NSLog(@"res = %@", res);
  • 运算符:可以获取数组中的最大值,最小值,平均值
    id res1 = [arr valueForKeyPath:@"@avg.money"];
    NSLog(@"res = %@", res1);

2.通过KVC赋值

  • 给属性赋单个词

     //      KVC == KEY VALUE CODING
     // Value : 值, 只能传对象
     // forKey: 需要给谁(哪个属性)赋值
     // setValue:forKey:方法, 只能给对象的直接属性赋值
     [p setValue:@"lmj" forKey:@"name"];
     // @(998.0) == [NSNumber numberWithDouble:(double)]
     [p setValue:@(668.0) forKey:@"money"];
  • 多层赋值
     //    p.dog.name == [[p dog] setName:]
     //    p.dog.name = @"wangwang";
     //    p.dog.price = 110.0;
     setValue:forKeyPath: 可以给对象的间接属性赋值. 多层赋值
     // 建议: 以后在开发中都使用setValue:forKeyPath:
     //    [p setValue:@"xiaoqiang"        forKeyPath:@"dog.name"];
     //    [p setValue:@(110) forKeyPath:@"dog.price"];

#pragma mark 给私有成员变量赋值
    /*
     //    [p setValue:@"lnj" forKey:@"_name"];
     //    [p setValue:@(30) forKey:@"_age"];

     //    SEL sel = @selector(say);
     //    [p performSelector:sel];
     //    [p say];
     */
  • pragma mark 字典转模型
    NSDictionary *dict = @{
                           @"name":@"xxx",
                           @"money": @(998.1),
                           //                           @"score":@(100)
                           @"dog":@{
                                   @"name":@"wangcai",
                                   @"price":@(110)
                                   }
                           };

    //    p.name = dict[@"name"];
    //    p.money = [dict[@"money"] doubleValue];
  • 注意点:

    • 如果想使用KVC进行字典转模型, 那么字典中的key必须和模型中的属性一模一样(个数 + 名称),不然会报一个经典错误
    this class is not key value coding-compliant for the key score.
  • 如果使用KVC进行字典转模型, 只能对当前调用KVC方法的对象进行转换, 不能对它的属性的对象进行转换

    • setValuesForKeysWithDictionary:方法内部的实现原理
    • 会拿到字典中的key, 然后根据这个key取出字典中的值, 然后再根据这个key赋值给对象
    [p setValue:@"xxx" forKey:@"name"];
    [p setValuesForKeysWithDictionary:dict];

二:KVO

    // KVO == Key Value Observing
    // 作用: 可以监听某个对象属性的改变

    Person *p = [Person new];
    p.name = @"lnj";
    p.age = 30;

    /*
     第一个参数: 告诉系统哪个对象监听
     第二个参数: 监听当前对象的哪个属性
     第三个参数: 监听到属性改变之后, 传递什么值
     第四个参数: 需要传递的参数 (这个参数不是传递给属性的)
     */
    // 给p这个对象添加一个监听 , 监听p对象的age属性的改变, 只要age属性改变就通知self
    [p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];

    p.age = 50;

    NSLog(@"-------------------");

    //p.age = 100;

    // 注意: 如果使用KVO监听某个对象的属性, 当对象释放之前一定要移除监听
    //  reason: 'An instance 0x7f9483516610 of class Person was deallocated while key value observers were still registered with it.
    // 注意: KVO只能监听通过set方法修改的值
    /*
     KVO的原理:
     只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象,
     并且重写自动生成的子类对象的被监听属性的set方法, 然后在set方法中通知监听者
     内部实现原理:会再setter方法中实现两个方法
     - (void)setName:(NSString *)name
     {
     [self willChangeValueForKey:@"name"];

     _name = name;

     [self didChangeValueForKey:name];
     }
     NSKVONotifying_Person
     */
    p->_age = 998;// (不能监听没有实现setter方法的属性)

    // 从p对象上移除self对它的age属性的监听
    [p removeObserver:self forKeyPath:@"age"]; // (一定要在对象释放前移除,不然运行会报错)

}

// 只要监听到属性的改变就会调用
// keyPath: 被监听的属性名称
// object : 被监听的对象
// context: 注册监听的时候传入的值
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
    NSLog(@"keyPath = %@, object = %@ , change = %@, context = %@", keyPath, object, change, context);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值