Связать @привязку с @Published с помощью SwiftUI

#swiftui #combine

#swiftui #объединить

Вопрос:

Я пытаюсь выяснить, как связать @Binding переданное в пользовательское представление @Published с моделью этого представления. По сути, я пытаюсь создать текстовое поле только для повторного использования. Я использую приведенный ниже код, который работает для установки целочисленного значения в текстовое поле, но чего я не могу понять, так это как обновить привязку при изменении текста.

 private class IntegerTextFieldValue: ObservableObject {
    @Published var value = "" {
        didSet {
            let numbersOnly = value.filter { $0.isNumber }
            if value != numbersOnly {
                value = numbersOnly
            }
        }
    }
}

struct IntegerTextField: View {
    @Binding var value: Int?
    @StateObject private var fieldValue = IntegerTextFieldValue()

    var placeholder = ""

    var body: some View {
        TextField(placeholder, text: $fieldValue.value)
            .keyboardType(.numberPad)
            .onAppear {
                if let value = value {
                    fieldValue.value = "(value)"
                }
            }
    }
}
 

Ответ №1:

Если я вас правильно понял

 .onChange (of: fieldValue.value) { vl in
    value = vl
}
 

этот модификатор обновляет привязку value до $fieldValue.value

Комментарии:

1. onChange принимает значение, а не привязку. Однако ваш ответ здесь, по сути, дал мне то, что мне нужно, используя .onChange(of: fieldValue.value) { value = Int($0) }

Ответ №2:

Вот измененный код для демонстрации возможного подхода (протестирован с Xcode 12.1 / iOS 14.1):

 private class IntegerTextFieldValue: ObservableObject {
    @Published var value = "" {
        didSet {
            let numbersOnly = value.filter { $0.isNumber }
            if value != numbersOnly {
                value = numbersOnly
            }

            if let number = Int(value) {
                numberValue = number
            }
        }
    }
    
    @Published var numberValue: Int = 0
}

struct IntegerTextField: View {
    @Binding var value: Int?
    @StateObject private var fieldValue = IntegerTextFieldValue()

    var placeholder = ""

    var body: some View {
        TextField(placeholder, text: $fieldValue.value)
            .keyboardType(.numberPad)
            .onAppear {
                if let value = value {
                    fieldValue.value = "(value)"
                }
            }
            .onChange(of: fieldValue.numberValue) {
                if $0 != self.value {
                    self.value = $0
                }
            }
    }
}