我需要上传图片,并在按钮点按下将项目保存到数据库。
我不确定我是否采取了正确的方法。我应该分开上传请求吗?在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! }
}
}
通过组合最新的内部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)
}