Swift dynamicMemberLookup

类或是struct声明为 @dynamicMemberLookup 后,并实现 subscript(dynamicMember:), 就可以用带 点的语法来访问对应的数据了。

  • 实现dynamicMemberLookup 的类:
@dynamicMemberLookup
class TestData<Value> {
    var value : Value
    var name : String
    
    init(_ v : Value, name : String) {
        self.value = v
        self.name = name
    }
    //subscript(dynamicMember:) 只能用 String 或 KeyPath 作为参数
    subscript(dynamicMember pro : String) -> Bool {
        return true
    }
    
    subscript<T>(dynamicMember key : KeyPath<Value, T>) -> T {
        value[keyPath: key]
    }
}
  • 使用方法
//使用带点语法访问数据时有优先级
let data = TestData("b", name: "haha”)    //Value 泛型推导为 “b”的类型,也就是String
//优先级1: 访问已有的属性,比如 TestData 的name属性。
let name = data.name
//优先级2: 访问 keypath对应的 Value类型所拥有的属性。 这里Value是String,那么count 访问的就是 value.count
let count = data.count  //值为1
//优先级3: 访问 String类型参数的subscript
let value = data.haha //返回 true

总结:

  1. dynamicMemberLookup 是否安全? 是安全的。 如果用String 来访问,那么在实现的 subscript 里确保了返回数据是安全的。 如果用keyPath 访问,不存在的keyPath 无法通过编译。

  2. 可以声明多个 相同参数类型,但不同返回值的subscript。编译时通过返回值来区分调用哪个subscript let b : Bool = data.haha let c : String = data.haha

  3. 不能给已有类和结构添加 dynamicMemberLookup 功能