zoukankan      html  css  js  c++  java
  • KVC 总结

    认识 KVC

    KVC (Key-Value Coding), 它是一种用间接方式访问类的属性的机制。在 Swift 中为一个类实现 KVC 的话,需要让它继承自 NSObject:

    class Person: NSObject {
    var firstName: String
    var lastName: String
    init(firstName: String, lastName: String) {
    self.firstName = firstName
    self.lastName = lastName
    }
    }
    

    这样,我们就可以使用 KVC 的方式访问 Person 类的属性了:

    let p = Person(firstName: "Lucky", lastName: "Roc")
    //使用 KVC 机制赋值的方式
    p.setValue("swift", forKey: "firstName")
    // 使用直接引用属性的方式
    print(p.lastName)
    // 使用 KVC 机制访问的方式
    print(p.valueForKey("lastName")!)
    

    KVC 有什么用?

    可以不用过多的依赖编译时的限制,为我们提供了更多的运行时的能力,免去我们调用gettersetter方法,从而简化我们的代码,也可以用来修改系统控件内部属性(这个黑魔法且用且珍惜)。

    KVC的运行机制

    setValue: forKey

    let p = Person(firstName: "Lucky", lastName: "Roc")
    //使用 KVC 机制赋值的方式
    p.setValue("swift", forKey: "firstName")
    

    总结: 如果没有找到Set<Key>方法的话,会按照_key_iskeykeyiskey的顺序搜索成员并进行赋值操作

    valueForKey

    let p = Person(firstName: "Lucky", lastName: "Roc")
    print(p.valueForKey("lastName")!)
    

    valueForKeyPath

    在开发过程中,一个类的成员变量有可能是其他的自定义类,你可以先用KVC获取出来该属性,然后再次用KVC来获取这个自定义类的属性,但这样是比较繁琐的,对此,KVC提供了一个解决方案,那就是键路径KeyPath

    class Address: NSObject {
    var firstLine: String
    var secondLine: String
    init(firstLine: String, secondLine: String) {
    self.firstLine = firstLine
    self.secondLine = secondLine
    }
    }
    
    class PersonHandleKeyPath: NSObject {
    var firstName: String
    var lastName: String
    var address: Address
    init(firstName: String, lastName: String, address: Address) {
    self.firstName = firstName
    self.lastName = lastName
    self.address = address
    }
    }
    
    var p = PersonHandleKeyPath(firstName: "Lucky", lastName: "Roc", address: Address(firstLine: "Nanjing", secondLine: "ZhujiangRoad"))
    print(p.valueForKeyPath("address.firstLine")!)
    

    KVC的异常处理

    p.setValue(nil, forKey: "firstName")
    p.valueForKey("age")!
    

    以上的2个方法都会导致Crash,为了避免Crash我们通常会重写如下的2个方法

    //如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
    - (nullable id)valueForUndefinedKey:(NSString *)key;
    
    //如果你在SetValue方法时给Value传nil,则会调用这个方法
    - (void)setNilValueForKey:(NSString *)key;
    

    KVC和Runtime的关系

    [dic setVaule:@"zhangsan" forKey:@"name"];
    

    当运行的时候就会被编译成

    // 根据方法名找到运行方法的时候所需要的环境参数
    SEL sel = sel_get_uid("setValue:forKey:");
    // 从自己isa指针结合环境参数,找到具体的方法实现接口
    IMP method = objc_msg_lookup(dic->isa,sel);
    method(dic,sel,@"zhangsan",@"name");
    

    KVC使用场景

    单层字典模型转化(字典转model)

    [self.loginModel setValuesForKeysWithDictionary:resultDic];
    

    (iOS黑魔法) 通过RunTime获取控件API未暴露的属性,自定义修改

    例:通过KVC拿到UITextField的占位label,修改颜色
    UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
    placeholderLabel.textColor = [UIColor redColor];
    

    使用valueForKeyPath可以获取数组中的最小值、最大值、平均值、求和

    CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
    CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
    CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
    CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
    

    KVC相关面试题

    在KVC 中如何保持程序的健壮性?

    重写对象的valueforkey和setvalueforkey方法。

    KVC 中的隐藏方法有什么?

    max,min,count,sum 等

  • 相关阅读:
    Jasmine入门(上)
    手把手教你如何安装和使用Karma-Jasmine
    AngularJS入门之动画
    AngularJS入门之Services
    AngularJS入门之数据验证
    AngularJS入门之数据绑定
    AngularJS的Filter用法详解
    WPF快速实现XML可视化编辑工具
    AngularJS自定义Directive
    低级错误总结
  • 原文地址:https://www.cnblogs.com/penger/p/10276687.html
Copyright © 2011-2022 走看看