title: Combining Observables in RxSwift
body: <p>I need to upload image, and save Item to database on button tap. 
  Not sure if I have taken the right approach here. Should I separate the upload request? Is it safe to emit an event in the <code>do(onNext:)</code> <code>operator</code> since its all async? I also need to account for errors, and the only place I do that is when I save Item. I'm banking on any error propagating. Also, Saving Item is a cold observable, so do I need to subscribe to it from the view Model to actually execute the request? It just returns an <code>Observable&lt;Void&gt;</code>.  </p>
  
  <pre><code>class AddItemViewModel {
  
      private let dispatcher = FirebaseDispatcher()
  
      var error: Observable&lt;Error&gt;?
  
      init() {
  
      }
  
      // - Add Item
      // 1. upload Image
      // 2. combine imageUrl with other input observables
      // 3. Construct Item &amp; emit in `do` operator? 
      // 4. Save Item
      //
      func addItem(title: Observable&lt;String?&gt;, price: Observable&lt;String?&gt;, tags: Observable&lt;String?&gt;, info: Observable&lt;String?&gt;, weeks: Observable&lt;Int&gt;, image: Observable&lt;UIImage?&gt;, didPressAddButton: Observable&lt;Void&gt;) {
  
          let item = image.flatMapLatest { image -&gt; Observable&lt;Item&gt; in
  
              return Observable&lt;Item&gt;.create { observer in
  
                  if let image = image, let imageData = UIImageJPEGRepresentation(image, 0.8) {
                      // 1
                      let imageUrl = ImageAPI.uploadImage(data: imageData, type: .item)
  
                      _ = Observable.combineLatest(title, price, tags, info, weeks, imageUrl) {
                          (title, price, tags, info, weeks, imageUrl) -&gt; Item? in
                          // 3
                          if let title = title, let price = price, let tags = tags, let info = info, let weeks = Weeks(rawValue: weeks), let expirationDate = weeks.timeInterval {
  
                              let tagsArray = tags.components(separatedBy: ",") as NSArray
  
                              let currentUser = AuthService.shared.currentUser
                              let id = NSUUID().uuidString
                              let ownerId = currentUser.id
                              let ownerRating = currentUser.rating
                              let ownerName = currentUser.name
                              let ownerProfileImageUrl = currentUser.profileImageUrl
                              let creationDate = Date().timeIntervalSince1970 as Double
                              let bidCount = 0
                              let location = currentUser.location
  
                              let item = Item(id: id, ownerId: ownerId, ownerRating: ownerRating, ownerName: ownerName, ownerProfileImageUrl: ownerProfileImageUrl, creationDate: creationDate, expirationDate: expirationDate, title: title, price: price, info: info, imageUrl: imageUrl, bidCount: bidCount, tags: tagsArray, location: location)
  
                              return item
  
                          } else {
                              observer.onError(CustomError.invalidItem)
                              return nil
                          }
                          }.filter { $0 != nil }.map { $0! }
  
                          // Is this proper way to emit element?
                          .do(onNext: {
                              observer.onNext($0)
                          })
                  } else {
                      observer.onError(CustomError.invalidImage)
                  }
                  return Disposables.create()
              }
          }
  
  
  
          // 4
          let savedItem = didPressAddButton.withLatestFrom(item)
              .flatMap { item in
                  return SaveItemTask(data: item.toJSON() as [String : AnyObject], resource: .all).execute(in: self.dispatcher).materialize()
              }
  
          error = savedItem.filter { $0.error != nil }.map { $0.error! }
  
      }
  
  
  }
  </code></pre>
  
  <p><strong>Reduce arguments by combining latest inside ViewController</strong> </p>
  
  <pre><code>    private func bindInputs() {
  
      addButton.rx.tap.asObservable()
          .subscribe(onNext: {
              let itemInfo = Observable
                  .combineLatest(self.titleTextField.rx.text.asObservable(),
                                 self.priceTextField.rx.text.asObservable(),
                                 self.tagsTextField.rx.text.asObservable(),
                                 self.infoTextField.rx.text.asObservable(),
                                 self.weeksSegmentedControl.rx.selectedSegmentIndex.asObservable(),
                                 self.imageView.rx.observe(UIImage.self, "image"))
                  { (title, price, tags, info, weeks, image) -&gt; (String?, String?, String?, String?, Int, UIImage?) in
                      return (title, price, tags, info, weeks, image)
              }
              self.viewModel.saveItem(itemInfo)
          })
          .addDisposableTo(disposeBag)
  }
  </code></pre>