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 等

  • 相关阅读:
    el-select下拉框选项太多导致卡顿,使用下拉框分页来解决
    vue+elementui前端添加数字千位分割
    Failed to check/redeclare auto-delete queue(s)
    周末啦,做几道面试题放松放松吧!
    idea快捷键
    解决flink运行过程中报错Could not allocate enough slots within timeout of 300000 ms to run the job. Please make sure that the cluster has enough resources.
    用.net平台实现websocket server
    MQTT实战3
    Oracle 查看当前用户下库里所有的表、存储过程、触发器、视图
    idea从svn拉取项目不识别svn
  • 原文地址:https://www.cnblogs.com/penger/p/10276687.html
Copyright © 2011-2022 走看看