Я стремлюсь реализовать общий цикл проверки / вето в SwiftUI - такого рода вещи, которые должны быть довольно просты для использования с инфраструктурой «единого источника правды»
Короче говоря, я хочу:
- Иметь общий элемент управления (скажем, например,
TextField
) - Применить подтверждение / вето при обновлении этого элемента управления (например, пользователь вводит текст)
- Распространение предполагаемого изменения в валидатор, где-то обновляем исходный объект
Binding
(в идеале, элемент @State
внутри View
) - Передача этого значения обратно в элемент управления для отображения
Похоже, что для всего «единого источника правды» Apple в некотором роде лжет - внедрение этапа проверки в эту цепочку кажется трудным, особенно без нарушения инкапсуляции представления
Обратите внимание, что я действительно не хочу решать эту проблему , в частности - я ищу шаблон для реализации (то есть: замените String
и TextField
на Bool
d Toggle
например)
В следующем коде показана моя лучшая попытка выполнить вышеуказанный цикл
class ValidatedValue<T>: ObservableObject {
let objectWillChange = ObservableObjectPublisher()
var validator: (T, T)->T
var value: T {
get {
_value
}
set {
_value = validator(_value, newValue)
objectWillChange.send()
}
}
/// Backing value for the observable
var _value: T
init(_ value: T, validator: @escaping (T, T)->T) {
self._value = value
self.validator = validator
}
}
struct MustHaveDTextField: View {
@ObservedObject var editingValue: ValidatedValue<String>
public var body: some View {
return TextField(
"Must have a d",
text: $editingValue.value
}
}
с проверенным значением, определенным далеко за пределами области действия View
ValidatedValue(
"oddity has a d",
validator: { current, new in
if new.contains("d") {
return new
}
else {
return current
}
}
)
Этот вид работает, поскольку он не позволит вам изменить строковый ввод, если он не содержит "d" s. Тем не мение;
- Состояние курсора все еще перемещается в текстовом элементе управления после точки проверки
- Оно показывает, что должно быть полностью внутренним состоянием, и требует передачи этого от родителей или через
EnvironmentObject
(если вы делаете это с List
вещами ... ау)
Либо я что-то упускаю, либо я использую неправильный подход, либо Apple говорит, что это не такчто делает Apple.
Изменение внутреннего состояния во время цикла, как это делается здесь или здесь не хорошо - они изменяют состояние внутри цикла просмотра, который XCode помечает как undefined behaviour
. Этот также имеет аналогичное решение, но опять же страдает от необходимости помещать логику проверки вне представления - ИМХО, оно должно быть автономным.