带有 RxSwift 的 MVVM
Posted
技术标签:
【中文标题】带有 RxSwift 的 MVVM【英文标题】:MVVM with RxSwift 【发布时间】:2018-04-29 08:26:49 【问题描述】:我正在尝试理解 mvvm + RxSwift 但我有一些问题。
我目前正在使用这种方法,我不确定它是否正确或可以更好。我该怎么做才能喜欢对方法进行分组,我的意思是,可能类似于 doFirst(loading = true).doNext(getData).doLast(loading = false).catch(apiError) 然后订阅此事件?有可能吗?
视图控制器:
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
viewModel = UsersViewModel(apiService: apiService)
configureBindings()
func configureBindings()
tableView.delegate = nil
tableView.dataSource = nil
viewModel.isLoading.bind(to: loadingView.rx.isAnimating)
.disposed(by: disposeBag)
viewModel.models
.bind(to: tableView.rx.items(cellIdentifier: "userCell", cellType: UserCell.self)) (_, _, cell) in
print("Binding the cell items")
.disposed(by: disposeBag)
tableView.rx.modelSelected(User.self).subscribe(onNext: value in
print(value)
).disposed(by: disposeBag)
viewModel.error.filterNil().subscribe(onNext: (err) in
self.tableView.backgroundView = EmptyView(title: "No Users", description: "No users found")
print("Showing empty view...")
print(err)
).disposed(by: disposeBag)
然后在我的 UsersViewModel 中:
class UsersViewModel
var models: Observable<[User]>
return modelsVariable.asObservable()
var isLoading: Observable<Bool>
return isLoadingVariable.asObservable()
var error: Observable<ApiError?>
return errorVariable.asObservable()
private var modelsVariable = BehaviorRelay<[User]>(value: [])
private var isLoadingVariable = BehaviorRelay<Bool>(value: false)
private var errorVariable = BehaviorRelay<ApiError?>(value: nil)
// MARK: - Data Manager
var apiService: API
required init(apiService: API)
self.apiService = apiService
isLoadingVariable.accept(true)
apiService.GET(EndPoints.USER_LIST, type: Several<User>.self)
.subscribe(onNext: (model) in
self.isLoadingVariable.accept(false)
self.modelsVariable.accept(model.items)
, onError: (err) in
self.isLoadingVariable.accept(false)
self.errorVariable.accept(err as? ApiError)
)
我的“GET”函数只返回一个Observable<Several<User>>.
几个:
struct Several
var items: [User]
有什么可以改进的吗?
【问题讨论】:
【参考方案1】:有点难以理解您在问什么,但是如果您担心 init
方法的命令性,并希望将您的 API 调用包装成可以重复的连续 Observable 序列,您可以这样做:
class UsersViewModel
//...
var fetchUsersObserver: AnyObserver<Void>
return fetchUsersSubject.asObserver()
//...
private let fetchUsersSubject = PublishSubject<Void>()
private let disposeBag = DisposeBag()
//...
required init(apiService: API)
self.apiService = apiService
bindFetchUsers()
private func bindFetchUsers()
fetchUsersSubject
.asObservable()
.do(onNext: [weak self] _ in self?.isLoadingVariable.accept(true) )
.flatMap(self.fetchUsers)
.do(onNext: [weak self] _ in self?.isLoadingVariable.accept(false) )
.bind(to: modelsVariable)
.disposed(by: disposeBag)
private func fetchUsers() -> Observable<[User]>
return apiService
.GET(EndPoints.USER_LIST, type: Several<User>.self)
.map $0.items
.catchError [weak self] error in
self?.errorVariable.accept(error as? ApiError)
return .just([])
那么,你只需要将一个控件绑定到这个AnyObserver
,或者手动给它发送一个事件:
func configureBindings()
// from a control, such as UIButton
someButton
.rx
.tap
.bind(to: viewModel.fetchUsersObserver)
.disposed(by: disposeBag)
// manually
viewModel.fetchUsersObserver.onNext(())
脚注 1:我通常喜欢将我的视图模型设为 struct
s,这样我就不必担心所有 [weak self]
语句。
脚注 2:注意fetchUsers()
函数如何捕获任何抛出的错误,并且不让错误传播到外部 Observable 序列。这一点很重要,因为如果这个外部 Observable 发出一个 error
事件,它就永远不会发出另一个 next
事件。
【讨论】:
以上是关于带有 RxSwift 的 MVVM的主要内容,如果未能解决你的问题,请参考以下文章