【问题标题】:MVVM with RxSwift带有 RxSwift 的 MVVM
【发布时间】: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&lt;Several&lt;User&gt;&gt;.

几个:

struct Several {
    var items: [User]
}

有什么可以改进的吗?

【问题讨论】:

    标签: ios swift observable alamofire rx-swift


    【解决方案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:我通常喜欢将我的视图模型设为 structs,这样我就不必担心所有 [weak self] 语句。

    脚注 2:注意fetchUsers() 函数如何捕获任何抛出的错误,并且不让错误传播到外部 Observable 序列。这一点很重要,因为如果这个外部 Observable 发出一个 error 事件,它就永远不会发出另一个 next 事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多