title: Best data-binding practice in Combine + SwiftUI?
body: <p>In RxSwift it's pretty easy to bind a <code>Driver</code> or an <code>Observable</code> in a <code>View Model</code> to some observer in a <code>ViewController</code> (i.e. a <code>UILabel</code>).</p>
  
  <p>I usually prefer to build a pipeline, with observables <strong>created from other observables</strong>, instead of "imperatively" pushing values, say via a <code>PublishSubject</code>).</p>
  
  <p>Let's use this example: <strong>update a <code>UILabel</code> after fetching some data from the network</strong></p>
  
  <hr>
  
  <h2>RxSwift + RxCocoa example</h2>
  
  <pre class="lang-swift prettyprint-override"><code>final class RxViewModel {
      private var dataObservable: Observable&lt;Data&gt;
  
      let stringDriver: Driver&lt;String&gt;
  
      init() {
          let request = URLRequest(url: URL(string:"https://www.google.com")!)
  
          self.dataObservable = URLSession.shared
              .rx.data(request: request).asObservable()
  
          self.stringDriver = dataObservable
              .asDriver(onErrorJustReturn: Data())
              .map { _ in return "Network data received!" }
      }
  }
  </code></pre>
  
  <pre class="lang-swift prettyprint-override"><code>final class RxViewController: UIViewController {
      private let disposeBag = DisposeBag()
      let rxViewModel = RxViewModel()
  
      @IBOutlet weak var rxLabel: UILabel!
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
          rxViewModel.stringDriver.drive(rxLabel.rx.text).disposed(by: disposeBag)
      }
  }
  </code></pre>
  
  <hr>
  
  <h2>Combine + UIKit example</h2>
  
  <p>In a UIKit-based project it seems like you can keep the same pattern:</p>
  
  <ul>
  <li>view model exposes publishers</li>
  <li>view controller binds its UI elements to those publishers</li>
  </ul>
  
  <pre class="lang-swift prettyprint-override"><code>final class CombineViewModel: ObservableObject {
      private var dataPublisher: AnyPublisher&lt;URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure&gt;
      var stringPublisher: AnyPublisher&lt;String, Never&gt;
  
      init() {
          self.dataPublisher = URLSession.shared
              .dataTaskPublisher(for: URL(string: "https://www.google.it")!)
              .eraseToAnyPublisher()
  
          self.stringPublisher = dataPublisher
              .map { (_, _) in return "Network data received!" }
              .replaceError(with: "Oh no, error!")
              .receive(on: DispatchQueue.main)
              .eraseToAnyPublisher()
      }
  }
  </code></pre>
  
  <pre class="lang-swift prettyprint-override"><code>final class CombineViewController: UIViewController {
      private var cancellableBag = Set&lt;AnyCancellable&gt;()
      let combineViewModel = CombineViewModel()
  
      @IBOutlet weak var label: UILabel!
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
          combineViewModel.stringPublisher
              .flatMap { Just($0) }
              .assign(to: \.text, on: self.label)
              .store(in: &amp;cancellableBag)
      }
  }
  </code></pre>
  
  <hr>
  
  <h2>What about SwiftUI?</h2>
  
  <p>SwiftUI relies on property wrappers like <code>@Published</code> and protocols like <code>ObservableObject</code>, <code>ObservedObject</code> to automagically take care of bindings (As of <em>Xcode 11b7</em>).</p>
  
  <p>Since (AFAIK) property wrappers cannot be "created on the fly", there's no way you can re-create the example above using to the same pattern.
  The following <strong>does not compile</strong></p>
  
  <pre class="lang-swift prettyprint-override"><code>final class WrongViewModel: ObservableObject {
      private var dataPublisher: AnyPublisher&lt;URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure&gt;
      @Published var stringValue: String
  
      init() {
          self.dataPublisher = URLSession.shared
              .dataTaskPublisher(for: URL(string: "https://www.google.it")!)
              .eraseToAnyPublisher()
  
          self.stringValue = dataPublisher.map { ... }. ??? &lt;--- WRONG!
      }
  }
  </code></pre>
  
  <p>The closest I could come up with is <strong>subscribing in your view model (UGH!)</strong> and <strong>imperatively update your property</strong>, which does not feel right and reactive at all.</p>
  
  <pre class="lang-swift prettyprint-override"><code>final class SwiftUIViewModel: ObservableObject {
      private var cancellableBag = Set&lt;AnyCancellable&gt;()
      private var dataPublisher: AnyPublisher&lt;URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure&gt;
  
      @Published var stringValue: String = ""
  
      init() {
          self.dataPublisher = URLSession.shared
              .dataTaskPublisher(for: URL(string: "https://www.google.it")!)
              .eraseToAnyPublisher()
  
          dataPublisher
              .receive(on: DispatchQueue.main)
              .sink(receiveCompletion: {_ in }) { (_, _) in
              self.stringValue = "Network data received!"
          }.store(in: &amp;cancellableBag)
      }
  }
  </code></pre>
  
  <pre class="lang-swift prettyprint-override"><code>struct ContentView: View {
      @ObservedObject var viewModel = SwiftUIViewModel()
  
      var body: some View {
          Text(viewModel.stringValue)
      }
  }
  </code></pre>
  
  <p>Is the "old way of doing bindings" to be forgotten and replaced, in this new <strong>UIViewController-less</strong> world?</p>