Swift Combine 中的双向绑定

Two-way binding in Swift Combine

我有一个进度条和一个文本字段,两者都根据彼此的输入进行更新:

class ViewModel: ObservableObject {
    @Published var progressBarValue: Double {
        didSet {
            textFieldValue = String(progressBarValue)
        }
    }
    @Published var textFieldValue: String {
        didSet {
            progressBarValue = Double(progressBarValue)
        }
    }
}

由于更新一个更新另一个,我最终在我的代码中有一个无限递归。

有没有办法使用 Combine 或纯 swift 代码来解决这个问题?

也许避免循环的额外检查会起作用?

@Published var progressBarValue: Double {
    didSet {
        let newText = String(progressBarValue)

        if newText != textFieldValue {
            textFieldValue = newText
        }
    }
}
@Published var textFieldValue: String {
    didSet {
        if let newProgress = Double(textFieldValue),
            abs(newProgress - progressBarValue) > Double.ulpOfOne {
            progressBarValue = newProgress
        }
    }
}

扩展我的评论,这是一个滑块和文本字段的最小示例,它们都通过双向绑定控制(并被控制)一个值:

class ViewModel: ObservableObject {
    @Published var progress: Double = 0
}

struct ContentView: View {
    @EnvironmentObject var model: ViewModel

    var body: some View {
        VStack {
            TextField("", value: self.$model.progress, formatter: NumberFormatter())
            Slider(value: self.$model.progress, in: 0...100)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(ViewModel())
    }
}

请注意,我还必须在 AppDelegate 上向我的环境中注入一个 ViewModel 实例才能使其正常工作(在预览版和实际应用程序中)