我需要上传图片,并在按钮点击上将项目保存到数据库 . 我不确定我是否采取了正确的方法 . 我应该分开上传请求吗?因为它的所有异步,所以在 do(onNext:) operator 中发出事件是否安全?我还需要考虑错误,我唯一能做的就是保存项目 . 我对任何错误传播都很感兴趣 . 此外,保存项目是一个冷可观察,所以我需要从视图模型订阅它以实际执行请求吗?它只返回 Observable<Void> .

class AddItemViewModel {

    private let dispatcher = FirebaseDispatcher()

    var error: Observable<Error>?

    init() {

    }

    // - Add Item
    // 1. upload Image
    // 2. combine imageUrl with other input observables
    // 3. Construct Item & emit in `do` operator? 
    // 4. Save Item
    //
    func addItem(title: Observable<String?>, price: Observable<String?>, tags: Observable<String?>, info: Observable<String?>, weeks: Observable<Int>, image: Observable<UIImage?>, didPressAddButton: Observable<Void>) {

        let item = image.flatMapLatest { image -> Observable<Item> in

            return Observable<Item>.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) -> 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! }

    }


}

Reduce arguments by combining latest inside ViewController

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) -> (String?, String?, String?, String?, Int, UIImage?) in
                    return (title, price, tags, info, weeks, image)
            }
            self.viewModel.saveItem(itemInfo)
        })
        .addDisposableTo(disposeBag)
}