动态成员查找与动态方法调用 - ShenYj/ShenYj.github.io GitHub Wiki

动态成员查找与动态方法调用

@dynamicMemberLookup

动态成员查找是Swift 4.2版本后增加的新特性, 这个特性使得使用Swift语言在访问类、结构体或枚举等属性时, 更具动态化。

class Person {
    var name: String = ""
    var age: Int = 0
}

let person = Person()
print(person.name)

let sex: String = person.sex // Value of type 'Person' has no member 'sex'
print(sex)

如上所示代码, Person中并没有sex属性, 因此在let sex: String = person.sex这行报错

通过@dynamicMemberLookup修饰类后, 可以为数据结构增加动态成员查找的能力,

@dynamicMemberLookup
class Person {
    var name: String = ""
    var age: Int = 0
    
    // @dynamicMemberLookup attribute requires 'Person' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path
    subscript(dynamicMember member: String) -> String { "unknow" }
}

let person = Person()
print(person.name)

let sex: String = person.sex
print(sex)

除了增加@dynamicMemberLookup关键字外, 还实现了subscript(dynamicMember:)方法, 否则在编译时会有注释中的报错

通过给定查找不存在的属性时的默认值后, 在使用一个不存在的属性时,不再报错, 而是输出了给定的默认值

@dynamicCallable

动态方法调用与动态成员查找类似, 其实Swift 5.0版本之后引入的特性就不能访问不存在的属性一样,对于一般的数据类型,我们也不可以直接将其实例作为方法进行调用,除非其支持动态方法调用。

要支持动态方法调用, 我们需要实现dynamicallyCall(withArguments:)方法与dynamicallyCall(withKeywordArguments:)方法, 这两个方法的区别在于调用的时候是直接传入一组参数还是以键值对的方式传入参数。

@dynamicMemberLookup
@dynamicCallable
class Person {
    var name: String = ""
    var age: Int = 0
    
    // @dynamicMemberLookup attribute requires 'Person' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path
    subscript(dynamicMember member: String) -> String { "unknow" }
    
    // @dynamicCallable attribute requires 'Person' to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method
    func dynamicallyCall(withArguments arg: [String]) { print("unknow func: \(arg)") }
    func dynamiccallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) {
        let res = pairs.map{ key, value in "[\(key): \(value)]"}.joined(separator: "")
        print(res)
    }
}

let person = Person()
person("字符串参数", "a", "b")

继续上面的代码中修改后, 输出结果:

unknow func: ["字符串参数", "a", "b"]

动态成员查找和动态方法调用都使得Swift语言有了更加强大的动态性,我们可以通过动态成员查找在运行时获得要调用的方法和参数,在使用动态方法调用使其执行, 这种能力使得Swift编程有了更多的可能性。

⚠️ **GitHub.com Fallback** ⚠️