Search code examples
swiftswiftuicombine

Convert a @State into a Publisher


I want to use a @State variable both for the UI and for computing a value.

For example, let's say I have a TextField bound to @State var userInputURL: String = "https://". How would I take that userInputURL and connect it to a publisher so I can map it into a URL.

Pseudo code:

$userInputURL.publisher()
      .compactMap({ URL(string: $0) })
      .flatMap({ URLSession(configuration: .ephemeral).dataTaskPublisher(for: $0).assertNoFailure() })
      .eraseToAnyPublisher()

Solution

  • You can't convert @state to publisher, but you can use ObservableObject instead.

    import SwiftUI
    
    final class SearchStore: ObservableObject {
        @Published var query: String = ""
    
        func fetch() {
            $query
                .map { URL(string: $0) }
                .flatMap { URLSession.shared.dataTaskPublisher(for: $0) }
                .sink { print($0) }
        }
    }
    
    struct ContentView: View {
        @StateObject var store = SearchStore()
    
        var body: some View {
            VStack {
                TextField("type something...", text: $store.query)
                Button("search") {
                    self.store.fetch()
                }
            }
        }
    }