RxSwift项目实践

RxSwift-MVVM

这个项目是入坑RxSwift以来的一些收获,历经多个真实项目的实践。我也一直在为写出简洁易懂的代码而努力学习和实践,当中难免有不足之处希望得到社区开源爱好者的指点,期待在与你的探讨中也能获得一些收获

项目介绍

  • iOS 界面业务逻辑

    /*
     ViewController(action)
             ⏬ 
     Reactor(transform(action:))
             ⏬
     Reactor(mutate(action:)) 
             ⏬
     Reactor(transform(mutation:))
             ⏬
     Reactor(reduce(state: State, mutation: Mutation)) 
             ⏬
     Reactor(transform(state:))
             ⏬
     ViewController(state)
    */
    
    func bind(reactor: RepoListViewReactor) {
        // Action
        self.rx.viewDidLoad
            .map { Reactor.Action.refresh }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)
        
        // State
        reactor.state.map { $0.repos }
            .filterEmpty()
            .distinctUntilChanged()
            .map { [Section(model: (), items: $0)] }
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
    
    
  • Utility 通用工具集合

  • MVVMBase 项目基类

  • Networking 网络层封装

    /*
     service
        ⏬
     API(MVVMTargetType)
        ⏬
     Moya(TargetType)
    */ 
        service
            .repos(username: currentState.name, page: 1)
            .asObservable()
            .map(Mutation.setRepos)
    
  • Namespace 链式语法调用

        tableView
            .mvvm.adhere(toSuperView: view)
            .mvvm.layout(snapKitMaker: { (make) in
                make.edges.equalToSuperview()
            })
    

项目依赖

  • RxSwift/RxCocoa - Reactive Programming in Swift
  • RxOptional - RxSwift extensions for Swift optionals and "Occupiable" types
  • RxDataSources - UITableView and UICollectionView Data Sources for RxSwift (sections, animated updates, editing ...)
  • Moya/RxSwift - Network abstraction layer written in Swift
  • CocoaLumberjack/Swift - A fast & simple, yet powerful & flexible logging framework for Mac and iOS
  • Kingfisher - A lightweight, pure-Swift library for downloading and caching images from the web
  • SnapKit - A Swift Autolayout DSL for iOS & OS X
  • MJRefresh - An easy way to use pull-to-refresh
  • ReactorKit - A framework for a reactive and unidirectional Swift application architecture

ReactorKit is a combination of Flux and Reactive Programming. The user actions and the view states are delivered to each layer via observable streams. These streams are unidirectional: the view can only emit actions and the reactor can only emit states.

RxSwift项目实践_第1张图片
image

View

A View displays data. A view controller and a cell are treated as a view. The view binds user inputs to the action stream and binds the view states to each UI component. There's no business logic in a view layer. A view just defines how to map the action stream and the state stream.

To define a view, just have an existing class conform a protocol named View. Then your class will have a property named reactor automatically. This property is typically set outside of the view.

class ProfileViewController: UIViewController, View {
 var disposeBag = DisposeBag()
}

profileViewController.reactor = UserViewReactor() // inject reactor

When the reactor property has changed, bind(reactor:) gets called. Implement this method to define the bindings of an action stream and a state stream.

func bind(reactor: ProfileViewReactor) {
  // action (View -> Reactor)
  refreshButton.rx.tap.map { Reactor.Action.refresh }
    .bind(to: reactor.action)
    .disposed(by: self.disposeBag)

  // state (Reactor -> View)
  reactor.state.map { $0.isFollowing }
    .bind(to: followButton.rx.isSelected)
    .disposed(by: self.disposeBag)
}

Reactor

A Reactor is an UI-independent layer which manages the state of a view. The foremost role of a reactor is to separate control flow from a view. Every view has its corresponding reactor and delegates all logic to its reactor. A reactor has no dependency to a view, so it can be easily tested.

Conform to the Reactor protocol to define a reactor. This protocol requires three types to be defined: Action, Mutation and State. It also requires a property named initialState.

class ProfileViewReactor: Reactor {
  // represent user actions
  enum Action {
    case refreshFollowingStatus(Int)
    case follow(Int)
  }

 // represent state changes
  enum Mutation {
    case setFollowing(Bool)
  }

 // represents the current view state
  struct State {
    var isFollowing: Bool = false
  }

 let initialState: State = State()
}

An Action represents a user interaction and State represents a view state. Mutation is a bridge between Action and State. A reactor converts the action stream to the state stream in two steps: mutate() and reduce().

RxSwift项目实践_第2张图片
image

你可能感兴趣的:(RxSwift项目实践)