RxSwift ViewModel定义

RxSwift ViewModel定义

观察者模式

观察者模式目标:定义对象间一对多的依赖关系,当一个对象(被观察者)状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。

对于RxSwift就是序列事件(元素)的发出与订阅。

ViewModel定义

viewModel定义主要有两种方式,一种是初始化传入所有依赖,另一种是遵守ViewModelable协议,并且实现Input和Output的定义,在transform中进行绑定。

基于transform的ViewModel

遵守ViewModelable协议,或者自定义,绑定过程和逻辑处理在transform方法中,

优点: 输入输出明显,变化灵活,初始化时不需要传入其他参数。

ViewModelable

该协议用于规范Rx 情况下viewModel

public protocol ViewModelable {
    associatedtype Input      // 输入, 遵守时需要定义
    associatedtype Output     // 输出, 遵守时需要定义
    func transform(input: Input) -> Output         // 转换, 通过输入转化(绑定与逻辑)到输出
}

Intput: 逻辑依赖需要的东西

Output: 逻辑后的东西

NormalViewModel

由于大部分ViewModel都需要管理包, 和需要提供loading状态的被观察者,所以定义一个常用基本ViewModel,可以用于ViewModel继承。

public class NormalViewModel: NSObject {
    var disposeBag = DisposeBag()      // 管理包
    let loading: BehaviorRelay<Bool> = BehaviorRelay(value: false)  //loading状态(比如网络请求中,图片上传中)
}

关于disposeBag: 管理包的生命周期决定订阅的生命周期,注意ViewModel生命周期需要与视图一致,否则可能提早释放导致viewModel内部bag无法持有订阅。(即不可将vimeModel声明在方法内), 如果无法保证,则从外部传入disposeBag

TableViewModel

对于表格来说,可能具有是否有下一页、空白占位背景等通用属性。所以定义TableViewModel用于tableView的viewModel继承。

public class TableViewModel: NormalViewModel {
    /// 是否有下一页,分页使用
    let hasLastPage: BehaviorRelay<Bool> = BehaviorRelay(value: false)
    /// tableView空白占位,一共有三中状态, 无占位、无网络、无数据
    let noDataBackground: BehaviorRelay<UIScrollView.NoDataType> = BehaviorRelay(value: UIScrollView.NoDataType.hidden)
    /// 通知空白背景添加, 此时reload点击才有效
    ///
    /// **示例**
    /// ```
    ///  switch result {
    ///      case .failure(_):
    ///         self.noDataBackground.accept(.noNetwork)
    ///         self.noDataBackgroundAdd.accept(())
    ///      case .success(let models):
    ///         if models.isEmpty {
    ///             self.noDataBackground.accept(.noData)
    ///             self.noDataBackgroundAdd.accept(())
    ///         } else {
    ///             self.noDataBackground.accept(.hidden)
    ///             self.datasource.onNext(models)
    ///         }
    ///   }
    /// ```
    let noDataBackgroundAdd: BehaviorRelay<Void> = BehaviorRelay(value: ())
}
基于transform的ViewModel定义

参考RxSwiftExample ->LoginViewModel.swift 的LoginViewModel

// MARK: - 基于transform的ViewModel

class LoginViewModel: NormalViewModel, ViewModelable {
    struct Input {
        let username: ControlProperty<String>
        let password: ControlProperty<String>
        let login: ControlEvent<Void>
    }
    struct Output {
        let allowLogin: Driver<Bool>
    }
    func transform(input: Input) -> Output {
        input.login
            .subscribe(onNext: { (_) in
                print("网络请求")
            })
            .disposed(by: disposeBag)
        let allowLogin = Observable.combineLatest(input.username, input.password).flatMap { (username, password) -> Observable<Bool> in
            /// 假设用户名和密码都大于2 即可登录
            if username.count > 2 && password.count > 2 {
               return  Observable.just(true)
            } else {
               return  Observable.just(false)
            }
        }
        return Output(allowLogin: allowLogin.asDriver(onErrorJustReturn: true))
    }
}

基于初始化ViewModel

基于初始化的ViewModel,即在初始化时就传入依赖参数,bind和逻辑部分在初始化完成。

参考RxSwiftExample ->LoginViewModel.swift 的LoginViewModel1

// MARK: - 基于初始化的ViweModel

struct LoginViewModel1 {
    let disposeBag = DisposeBag()
    var allowLogin: Driver<Bool> = Driver.just(false)
    init(input:(username: ControlProperty<String>, password: ControlProperty<String>, login: ControlEvent<Void>)) {
        input.login
            .subscribe(onNext: { (_) in
                print("网络请求")
            })
            .disposed(by: disposeBag)
        allowLogin = Observable.combineLatest(input.username, input.password).flatMap { (username, password) -> Observable<Bool> in
            /// 假设用户名和密码都大于2 即可登录
            if username.count > 2 && password.count > 2 {
               return  Observable.just(true)
            } else {
               return  Observable.just(false)
            }
        }.asDriver(onErrorJustReturn: true)
    }
}

如何选择哪种方式?

建议使用基于transform实现ViewModelable,更加灵活和规范。当viewModel较为简单时,可以使用基于初始化。

参考项目:ViewModelDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值