I’m toying with a type-safe form library for iOS. The key idea is having a view model that the form is generic over:
struct ViewModel {
var addCustomNote: Bool
var customNote: String?
}
// Simplified example, ignoring sections
let form = Form<ViewModel>()
form.addRow(FormSwitchCell(keyPath: \.addCustomNote, title: "Add Custom Note"))
form.addRow(FormTextFieldCell(keyPath: \.customNote))
Now, the cells have various other properties that I would like to “bind” to the model, for example to hide cells that are not appropriate at the moment. For that I have an API like this:
// Cell will only appear when the the value at \.addCustomNote is true
form.addRow(FormTextFieldCell(keyPath: \.customNote)) { cell in
cell.bind(\.isVisible, to: \.addCustomNote)
}
Now to the point: The cells have some hierarchy, I have a base FormCell<Model>
and other cell types like FormTextFieldCell<Model>: FormCell<Model>
etc. The bind
method is defined on FormCell
:
public func bind<T>(
_ viewPath: WritableKeyPath<FormCell, T>,
to modelPath: KeyPath<Model, T>) {
// implementation
}
But that makes only possible to bind
the properties from the base FormCell
, whereas I would also like to bind properties introduced in FormCell
subclasses. In other words, I want something like this:
public func bind<T>(
_ viewPath: WritableKeyPath<Self, T>, // Self here instead of FormCell
to modelPath: KeyPath<Model, T>) {
// implementation
}
…but that’s not possible. I know I can do that as a free function (bind<Cell: FormCell>(…)
), but then the API kind of sucks, as I don’t know where to stick the free function and how the user is going to find it. How would you do this?