Проверка и вето SwiftUI для пользовательского ввода - PullRequest
0 голосов
/ 01 октября 2019

Я стремлюсь реализовать общий цикл проверки / вето в SwiftUI - такого рода вещи, которые должны быть довольно просты для использования с инфраструктурой «единого источника правды»

Короче говоря, я хочу:

  • Иметь общий элемент управления (скажем, например, TextField)
  • Применить подтверждение / вето при обновлении этого элемента управления (например, пользователь вводит текст)
  • Распространение предполагаемого изменения в валидатор, где-то обновляем исходный объект Binding (в идеале, элемент @State внутри View)
  • Передача этого значения обратно в элемент управления для отображения

Похоже, что для всего «единого источника правды» Apple в некотором роде лжет - внедрение этапа проверки в эту цепочку кажется трудным, особенно без нарушения инкапсуляции представления

Обратите внимание, что я действительно не хочу решать эту проблему , в частности - я ищу шаблон для реализации (то есть: замените String и TextField на Boold 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. Этот также имеет аналогичное решение, но опять же страдает от необходимости помещать логику проверки вне представления - ИМХО, оно должно быть автономным.

...