动态成员查找与动态方法调用 - ShenYj/ShenYj.github.io GitHub Wiki
动态成员查找是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:)
方法, 否则在编译时会有注释中的报错
通过给定查找不存在的属性时的默认值后, 在使用一个不存在的属性时,不再报错, 而是输出了给定的默认值
动态方法调用与动态成员查找类似, 其实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
编程有了更多的可能性。