Some thoughts about dynamic member lookup and nested structures.
Suppose that you have two different types that represent settings and data.
class Model {
struct Settings {
var setting1: Bool = false
var setting2: Bool = false
}
struct Data {
var value1: String = ""
var value2: String = ""
}
var settings: Settings
var data: Data
}
We can obviously add dynamic member lookup to access properties and, of course, perform actions after set values of these properties.
// MARK: Member Lookup
@dynamicMemberLookup
extension Model {
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Settings, T>) -> T {
get { self.settings[keyPath: keyPath] }
set {
self.settings[keyPath: keyPath] = newValue
self.didUpdateValues()
}
}
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Data, T>) -> T {
get { self.data[keyPath: keyPath] }
set {
self.data[keyPath: keyPath] = newValue
self.didUpdateValues()
}
}
}
// MARK: Calculations
extension Model {
func didUpdateValues() {
// perform any necessary computations on new values.
// utilize both data and settings values.
}
}
This scenario is related to decomposition of complex structures ( Hi, SwiftUI ). So far, so good. In ideal, we need a protocol or a generic type which utilizes protocol which exposes properties of structure.
// generated automatically when structure is in dynamicMemberLookup relationship.
// also it can contain any information about properties access ( write or readonly ).
protocol Model.Settings.PropertiesOnlyProtocol {
var setting1: Bool {get set}
var setting2: Bool {get set}
}
After that we can substitue structure by a dynamic-member-lookupable-type which adopts properties only protocol.
struct Usage {
var propertiesOfSettings: Model.Settings.PropertiesOnlyProtocol = Model()
}
// MARK: Settings
// generated automatically.
extension Settings: Model.Settings.PropertiesOnlyProtocol {}
// MARK: Model
// generated automatically in case of member lookup.
// it also can specify type of keypath. ( PropertiesOnlyProtocol.Writeable )
extension Model: Model.Settings.PropertiesOnlyProtocol {}