swiftuicombine

'Merge3' requires that 'Binding<Double>' conform to 'Publisher'


Minimal Code Used

import SwiftUI
import Combine

struct ContentView: View {
    @State private var value1: Double = 0
    @State private var value2: Double = 0
    @State private var value3: Double = 0

    var body: some View {
        VStack {
            // Your Test UI
        }
        .onReceive(calculateOnChange()) { _ in
            // ...
        }
    }

    private func calculateOnChange() -> AnyPublisher<Void, Never> {
        Publishers.Merge3($value1, $value2, $value3)
           .map { _ in () }
           .eraseToAnyPublisher()
    }
}

The error is

Generic struct 'Merge3' requires that 'Binding' conform to 'Publisher'

I don't understand why I am getting this error. Any help would be appreciated


Solution

  • Let's find out what type $value1 is:

    import Combine
    import SwiftUI
    
    struct ContentView: View {
        @State private var value1: Double = 0
    
        var body: some View {
            VStack {
                // Your Test UI
            }
        }
    
        func printType() {
            print("The type is \(type(of: $value1))")
        }
    }
    
    let content = ContentView()
    content.printType()
    

    Running this yields

    The type is Binding<Double>

    So $value1 is not a Publisher, it's a Binding.

    If you want to do something similar with publishers you could write it like this:

    import SwiftUI
    import Combine
    import PlaygroundSupport
    
    struct ContentView: View {
        @State var value1 = CurrentValueSubject<Double, Never>(0)
        @State var value2 = CurrentValueSubject<Double, Never>(0)
        @State var value3 = CurrentValueSubject<Double, Never>(0)
    
        var body: some View {
            VStack {
                Text("Hello")
            }
            .onReceive(calculateOnChange()) { value in
                print("The new value is \(value) ")
            }
        }
    
        private func calculateOnChange() -> AnyPublisher<Double, Never> {
            Publishers.Merge3(value1, value2, value3)
                .map { value in
                    return value
                }
                .eraseToAnyPublisher()
        }
    }
    
    let view = ContentView()
    PlaygroundSupport.PlaygroundPage.current.liveView = NSHostingView(rootView: view)
    
    view.value1.value = 3
    view.value2.value = 4
    view.value3.value = 5