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

Manual DI with ReactorKit

Avatar for masakazu sano masakazu sano
September 20, 2018
740

Manual DI with ReactorKit

Avatar for masakazu sano

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) }