本文最后更新于 2021年4月4日 晚上
                  
                
              
            
            
              
                
                ReactorKit 是一个基于 RxSwift 的状态管理框架,通过它可以实现单向数据流架构。
 
ReactorKit 框架使用概述 ReactorKit 是一个基于 RxSwift 的状态管理框架,通过它可以实现单向数据流架构。
在这样的架构下,核心还是从 View 上发送 Action 给 Reactor(Reducer),再通过 Reactor 改变状态, 通过新的状态驱动视图更新。
使用上非常简单,在某个视图控制器上(由于交互都是在视图控制器上实现的)继承 View, 然后它就有一个 reactor 属性了, 外界将某个视图对应的 reactor 挂接到视图上, 即可实现单向数据流的状态管理.
当外部赋值 reactor 时, 会触发调用 bind 方法, 在 bind 里面实现的就是 action 和 state 之间的绑定.
Reactor 被规定为必须实现三个子类型: Action, Mutation, State, 这三个类型在 Reactor 中进行转换: 
Action -> Mutation: func mutate(action: Action) -> Observable<Mutation>: 在 mutate 中执行相应的副作用操作, 如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func  mutate (action : Action ) -> Observable <Mutation > {   switch  action {   case  let  .refreshFollowingStatus(userID):      return  UserAPI .isFollowing(userID)        .map { (isFollowing: Bool ) -> Mutation  in          return  Mutation .setFollowing(isFollowing)        }      case  let  .follow(userID):     return  UserAPI .follow()       .map { _  -> Mutation  in          return  Mutation .setFollowing(true )       }   } }
 
通过 Mutation 改变 State: func reduce(state: State, mutation: Mutation) -> State: reduce 必须为纯函数.
公共状态处理 在这样的架构中没有公共状态处理的固定形式, 一般来说, 公共状态处理时, 可以通过外部创建管理公共状态的流, 比如通过 BehaviorSubject, 然后在外部公共位置持有. 如果需要这些公共状态, 直接读取就行, 要使用的时候可以在某个视图的 reactor 中通过如下方式处理:
1 2 3 func  transform (mutation : Observable <Mutation >) -> Observable <Mutation > {   return  Observable .merge(mutation, currentUser.map(Mutation .setUser)) }
 
View 之间的通信 在父子视图之间进行通信, 可以像如下这样进行(设 MessageInputView 为某个 ChatViewController 的子视图, 它也可以有自己的 reactor, 只要它是 View 类型的话):
1 2 3 4 5 6 extension  Reactive  where  Base : MessageInputView  {   var  sendButtonTap: ControlEvent <String > {     let  source =  base.sendButton.rx.tap.withLatestFrom(... )     return  ControlEvent (events: source)   } }
 
1 2 3 messageInputView.rx.sendButtonTap   .map(Reactor .Action .send)   .bind(to: reactor.action)
 
代码分析 Counter 示例 Counter 工程中在 AppDelegate 进行依赖注入:
1 2 3 4 5 func  application (_  application : UIApplication , didFinishLaunchingWithOptions  launchOptions : [UIApplication .LaunchOptionsKey : Any ]? ) -> Bool  {   let  viewController =  self .window? .rootViewController as!  CounterViewController    viewController.reactor =  CounterViewReactor ()   return  true  }
 
在 CounterViewController 中主要实现的就是 bind 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  func  bind (reactor : CounterViewReactor ) {               increaseButton.rx.tap                      .map { Reactor .Action .increase }         .bind(to: reactor.action)                .disposed(by: disposeBag)     decreaseButton.rx.tap       .map { Reactor .Action .decrease }       .bind(to: reactor.action)       .disposed(by: disposeBag)               reactor.state.map { $0 .value }          .distinctUntilChanged()       .map { "\($0 ) "  }                      .bind(to: valueLabel.rx.text)         .disposed(by: disposeBag)     reactor.state.map { $0 .isLoading }       .distinctUntilChanged()       .bind(to: activityIndicatorView.rx.isAnimating)       .disposed(by: disposeBag) }
 
这样的架构中, 可以把 View 的状态和公共状态完全分离开来.
针对 Reactor 中的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 final  class  CounterViewReactor : Reactor  {      enum  Action  {     case  increase     case  decrease   }      enum  Mutation  {     case  increaseValue     case  decreaseValue     case  setLoading(Bool )   }      struct  State  {     var  value: Int      var  isLoading: Bool    }   let  initialState: State    init () {     self .initialState =  State (       value: 0 ,        isLoading: false      )   }      func  mutate (action : Action ) -> Observable <Mutation > {     switch  action {     case  .increase:       return  Observable .concat([         Observable .just(Mutation .setLoading(true )),         Observable .just(Mutation .increaseValue).delay(.milliseconds(500 ), scheduler: MainScheduler .instance),         Observable .just(Mutation .setLoading(false )),       ])     case  .decrease:       return  Observable .concat([         Observable .just(Mutation .setLoading(true )),         Observable .just(Mutation .decreaseValue).delay(.milliseconds(500 ), scheduler: MainScheduler .instance),         Observable .just(Mutation .setLoading(false )),       ])     }   }      func  reduce (state : State , mutation : Mutation ) -> State  {     var  state =  state     switch  mutation {     case  .increaseValue:       state.value +=  1      case  .decreaseValue:       state.value -=  1      case  let  .setLoading(isLoading):       state.isLoading =  isLoading     }     return  state   } }
 
框架内部会在每个 Mutation 发射的时候调用 reduce, 通过 reduce 改变状态, 外部通过观察状态流从而实现视图更新, 所以一些重复性的工作都由框架帮忙完成了, 包括如下:
针对 Action 流中的事件去调用 mutate 
针对 Mutation 流中的事件去调用 reduce 
向外输出 State 流. 
 
实际 Reactor 的输入就是 Action, 输出就是 State, 它们都以流的方式呈现.
使用步骤简化如下:
建立 View
 
建立 Reactor
 
注入 Reactor(属性注入)
 
在 View 中 bind 方法内将外部事件 Map 为 Reactor 可以接收的 Action, 再通过 bind 绑定到 Reactor 的 action 流上(在输入这条线上不会出现错误事件, 详见 ActionSubject 的实现):
 1 2 3 4 public  final  class  ActionSubject <Element >: ObservableType , ObserverType , SubjectType  {      }
 
 
在 View 中的 bind 方法内将 Reactor 的输出 state 流按所需的属性进行 map 再绑定到某个具体视图上.
 
 
这样就完成整个流程, 相比手动实现的 MVVM 要方便很多.
特别是各层之间可以独立进行测试! View 可以 Mock, Reactor 可以 Mock, 当然服务层也可以单独测试.