Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Manual DI with ReactorKit

masakazu sano
September 20, 2018
600

Manual DI with ReactorKit

masakazu sano

September 20, 2018
Tweet

Transcript

  1. Masakazu Sano (@kz56cd) - iOS Developer - Freelance - like:

    - snowboard … - DbD (ps4) … - ଍ཪϚοαʔδ …
  2. "

  3. ֤DIύʔπͷ੹຿ʹ͍ͭͯ ViewControllerFactory func favoriteTop() -> FavoritesViewController { let viewController =

    StoryboardScene.FavoritesViewController.initialScene.instantiate() viewController.reactor = FavoritesViewReactor( favoriteService: components.favoriteService, userDefaultsService: components.userDefaultsService, errorHandler: components.errorHandler ) return viewController } protocol ViewControllerFactoryType { func favoriteTop() -> FavoritesViewController }
  4. ֤DIύʔπͷ੹຿ʹ͍ͭͯ CoordinatorFactory func favoriteCoordinator() -> FavoriteCoordinator { return FavoriteCoordinator( viewControllerFactory:

    viewControllerFactory ) } protocol CoordinatorFactoryType { func favoriteCoordinator() -> FavoriteCoordinator }
  5. Coordinator func start() { let viewController = viewControllerFactory.favoriteTop() navigationController.pushViewController(viewController, animated:

    true) _ = viewController.reactor? .routeSelected .subscribe(onNext: { [weak self] route in guard let self = self, let route = route else { return } switch route { case .photoDetail(let photoId): self.pushPhotoDetail(photoId: photoId) } }) }
  6. ViewController final class FavoritesViewController: UIViewController, StoryboardView { @IBOutlet weak var

    tableView: UITableView! var disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() } } // MARK: - ReactorKit extension FavoritesViewController { func bind(reactor: FavoritesViewReactor) { // Action self.tableView.rx.itemSelected .map { Reactor.Action.tapFavoritePhoto(row: $0.row) } .bind(to: reactor.action) .disposed(by: disposeBag) // State } }
  7. protocol FavoritesViewRouting { var routeSelected: Observable<FavoritesViewRouter?> { get } }

    enum FavoritesViewRouter { case photoDetail(photoId: Int) } extension FavoritesViewReactor: FavoritesViewRouting { } Reactor
  8. final class FavoritesViewReactor: Reactor { enum Action { case tapFavoritePhoto(row:

    Int) } enum Mutation { } struct State { var favoriteIds: [Int] } let routeSelected: Observable<FavoritesViewRouter?> let initialState: State private let userDefaultsService: UserDefaultsService private var routeSelectedSubject = PublishSubject<FavoritesViewRouter?>() init(userDefaultsService: UserDefaultsService) { self.userDefaultsService = userDefaultsService initialState = State(favoriteIds: userDefaultsService.getFavoriteIds()) routeSelected = routeSelectedSubject.asObservable() } }
  9. final class FavoritesViewReactor: Reactor { func mutate(action: Action) -> Observable<Mutation>

    { switch action { case .tapFavoritePhoto(let row): routeSelectedSubject.onNext( .spaceDetail(photoId: currentState.favoriteIds[row]!) ) return Observable.empty() } } func reduce( state: State, mutation: Mutation ) -> State { switch mutation { // no mutation cases } return state } } extension FavoritesViewReactor: FavoritesViewRouting { }
  10. 1. Reactor ͷมߋ final class FavoritesViewReactor: Reactor { enum Action

    { case actViewWillAppear case tapFavoritePhoto(row: Int) } enum Mutation { case setRoute(FavoriteViewRouter?) } struct State { var favoriteIds: [Int] } let routeSelected: Observable<FavoritesViewRouter?> let initialState: State private let userDefaultsService: UserDefaultsService private var routeSelectedSubject = PublishSubject<FavoritesViewRouter?>() // init͸লུ } Add Add
  11. 1. Reactor ͷมߋ final class FavoritesViewReactor: Reactor { enum Action

    { case actViewWillAppear case tapFavoritePhoto(row: Int) } enum Mutation { case setRoute(FavoriteViewRouter?) } struct State { var favoriteIds: [Int] } let routeSelected: Observable<FavoritesViewRouter?> let initialState: State private let userDefaultsService: UserDefaultsService private var routeSelectedSubject = PublishSubject<FavoritesViewRouter?>() // init͸লུ } Replace (into VC) Replace (into VC)
  12. func mutate(action: Action) -> Observable<Mutation> { switch action { case

    .actViewWillAppear: return Observable.just(.setRoute(nil)) case .tapFavoritePhoto(let row): return Observable.just( .setRoute( .spaceDetail( photoId: currentState.favoriteIds[row]! ) ) ) } } func reduce( state: State, mutation: Mutation ) -> State { var newState = state switch mutation { case .setRoute(let route): newState.route = route } return state } Add Add
  13. 2. ViewController ͷมߋ Add Add final class FavoritesViewController: UIViewController, StoryboardView

    { @IBOutlet weak var tableView: UITableView! private let viewWillAppearSubject = PublishSubject<Void>() private var routeSelectedSubject = PublishSubject<PhotoTopViewRouter>() var disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) viewWillAppearSubject.onNext(()) } } extension FavoritesViewController: FavoritesViewRouting { var routeSelected: Observable<FavoritesViewRouting> { return routeSelectedSubject.asObservable() } } Replace (by Reactor)
  14. 2. ViewController ͷมߋ Add Add final class FavoritesViewController: UIViewController, StoryboardView

    { @IBOutlet weak var tableView: UITableView! private let viewWillAppearSubject = PublishSubject<Void>() private var routeSelectedSubject = PublishSubject<PhotoTopViewRouter>() var disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) viewWillAppearSubject.onNext(()) } } extension FavoritesViewController: FavoritesViewRouting { var routeSelected: Observable<FavoritesViewRouting> { return routeSelectedSubject.asObservable() } } Add Add Add
  15. // MARK: - ReactorKit extension FavoritesViewController { func bind(reactor: FavoritesViewReactor)

    { // Action viewWillAppearSubject .map { Reactor.Action.actViewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) self.tableView.rx.itemSelected .map { Reactor.Action.tapFavoritePhoto(row: $0.row) } .bind(to: reactor.action) .disposed(by: disposeBag) // State reactor.state.map { $0.route } .distinctUntilChanged() .filter { $0 != nil } .subscribe(onNext: { [weak self] in self?.routeSelectedSubject.onNext($0!) }) .disposed(by: disposeBag) } } Add Add
  16. 3. ରԠ͢ΔCoordinator ͷมߋ (ϧʔςΟϯάՕॴ) func start() { let viewController =

    viewControllerFactory.favoriteTop() navigationController.pushViewController(viewController, animated: true) // NOTE: mod routing (replace reactor -> VC) _ = viewController .routeSelected .subscribe(onNext: { [weak self] route in guard let self = self else { return } switch route { case .photoDetail(let photoId): self.pushPhotoDetail(photoId: photoId) } }) .disposed(by: disposeBag) }
  17. 3. ରԠ͢ΔCoordinator ͷมߋ (ϧʔςΟϯάՕॴ) func start() { let viewController =

    viewControllerFactory.favoriteTop() navigationController.pushViewController(viewController, animated: true) // NOTE: mod routing (replace reactor -> VC) _ = viewController .routeSelected .subscribe(onNext: { [weak self] route in guard let self = self else { return } switch route { case .photoDetail(let photoId): self.pushPhotoDetail(photoId: photoId) } }) .disposed(by: disposeBag) }