Swift 中的动态成员查找
前言
我最喜欢 Swift 言语的一个特性是动态成员查找(dynamic member lookup)。尽管咱们并不常常运用它,但它经过改善咱们拜访特定类型数据的方法,显著改善了所供给类型的 API。
Glassfy:简化构建、办理和推广应用内购买。从订阅办理 SDK 到付费墙等完整的货币化东西。当即免费构建。
基础知识
假设咱们正在开发一个供给缓存功用的类型,并将其建模为名为 Cache 的结构体。
struct Cache {
var storage: [String: Data] = [:]
}
为了拜访缓存的数据,咱们调用存储特点的下标,该存储特点是 Dictionary 类型供给的。
var cache = Cache()
let profile = cache.storage["profile"]
在这里没有什么特别之处。咱们像曾经相同经过 Dictionary 类型的下标拜访字典。让咱们看看怎么运用 @dynamicMemberLookup
特点改善 Cache 类型的 API。
@dynamicMemberLookup
struct Cache {
private var storage: [String: Data] = [:]
subscript(dynamicMember key: String) -> Data? {
storage[key]
}
}
如上例所示,咱们运用 @dynamicMemberLookup
特点标记了 Cache 类型。咱们有必要实现具有 dynamicMember
参数并返回咱们需求的任何内容的下标。
var cache = Cache()
let profile = cache.profile
现在,咱们能够更方便地拜访 Cache 类型的配置文件数据。咱们的 API 的运用者可能会认为配置文件是 Cache 类型的特点,但事实并非如此。
此特性彻底在运行时作业,并利用了在点符号后键入的任何特点称号来拜访 Cache 类型的下标,该下标具有 dynamicMember 参数。
整个逻辑在运行时运行,编译期间的结果是不确定的。在运行时,您彻底能够决议应该从下标返回哪些数据以及怎么处理 dynamicMember 参数。
运用 KeyPath 的编译时安全性
咱们唯一能找到的缺陷是缺乏编译时安全性。咱们能够将 Cache 类型视为代码中键入的任何特点称号。走运的是,@dynamicMemberLookup
下标的参数不只能够是 String 类型,还能够是 KeyPath 类型。
@dynamicMemberLookup
final class Store\<State, Action>: ObservableObject {
typealias ReduceFunction = (State, Action) -> State
@Published private var state: State
private let reduce: ReduceFunction
init(
initialState state: State,
reduce: @escaping ReduceFunction
) {
self.state = state
self.reduce = reduce
}
subscript<T>(dynamicMember keyPath: KeyPath<State, T>) -> T {
state[keyPath: keyPath]
}
func send(_ action: Action) {
state = reduce(state, action)
}
}
如上例所示,咱们定义了承受强类型 KeyPath 实例的 dynamicMember 参数下标。在这种情况下,咱们答应 State 类型的 KeyPath,这有助于咱们取得编译时安全性。由于每逢咱们传递与 State 类型无关的过错 KeyPath 时,编译器都会显现过错。
struct State {
var products: \[String] = \[]
var isLoading = false
}
enum Action {
case fetch
}
let store: Store\<State, Action> = .init(initialState: .init()) { state, action in
var state = state
switch action {
case .fetch:
state.isLoading = true
}
return state
}
print(store.isLoading)
print(store.products)
print(store.favorites) // Compiler error
在上例中,咱们经过承受 KeyPath 的下标拜访 Store 的私有 state 特点。这看起来与前面的例子类似,但在这种情况下,只要您尝试拜访 State 类型的不可用特点,编译器就会显现过错。
总结
今日咱们学习了怎么运用 @dynamicMemberLookup
特点改善特定类型的 API。尽管并不是每个类型都需求它,但您能够谨慎运用它来改善 API。