본문 바로가기

iOS_RIBs

RIBs + ReactorKit을 활용한 RIBs 노드 中 Router

이전 포스팅인 " RIBs + ReactorKit을 활용한 RIBs 노드 中 Builder " 를 먼저 살펴보고 와야 이해가 됩니다.

해당 포스팅을 요약하자면 다음과 같습니다.

RIBs란 RIBs가 하나의 Node이고 RIBs Node의 트리 구조를 만들어 나가며(트리에 RIBs 노드를 attach, detach하면서), 앱을 설계해가는 프레임워크(?)라는 이해를 토대로 Builder에 대해서 설명했습니다.

 

이번엔 Router입니다.

2. Router

import RIBs

protocol SampleInteractable: Interactable {
  var router: SampleRouting? { get set }
  var listener: SampleListener? { get set }
}

protocol SampleViewControllable: ViewControllable {
}

final class SampleRouter: ViewableRouter<SampleInteractable, SampleViewControllable>, SampleRouting {
  override init(interactor: SampleInteractable, viewController: SampleViewControllable) {
    super.init(interactor: interactor, viewController: viewController)
    interactor.router = self
  }
}

Router의 샘플코드를 정의하였다.

  • Router : 자식 RIB를 attach, detach하여 RIBs 논리적 트리 구조를 형성합니다.

Router는 ViewableRouter 클래스를 상속받고, ViewableRouter는 다음과 같습니다.

import RxSwift

/// The base protocol for all routers that own their own view controllers.
public protocol ViewableRouting: Routing {
    var viewControllable: ViewControllable { get }
}

open class ViewableRouter<InteractorType, ViewControllerType>: Router<InteractorType>, ViewableRouting {

    public let viewController: ViewControllerType

    public let viewControllable: ViewControllable

    public init(interactor: InteractorType, viewController: ViewControllerType) {
        self.viewController = viewController
        guard let viewControllable = viewController as? ViewControllable else {
            fatalError("\(viewController) should conform to \(ViewControllable.self)")
        }
        self.viewControllable = viewControllable

        super.init(interactor: interactor)
    }

    // MARK: - Internal

    override func internalDidLoad() {
        setupViewControllerLeakDetection()

        super.internalDidLoad()
    }

    // MARK: - Private

    private var viewControllerDisappearExpectation: LeakDetectionHandle?

    private func setupViewControllerLeakDetection() {
        let disposable = interactable.isActiveStream
            .subscribe(onNext: { [weak self] (isActive: Bool) in
                guard let strongSelf = self else {
                    return
                }

                strongSelf.viewControllerDisappearExpectation?.cancel()
                strongSelf.viewControllerDisappearExpectation = nil

                if !isActive {
                    let viewController = strongSelf.viewControllable.uiviewController
                    strongSelf.viewControllerDisappearExpectation = LeakDetector.instance.expectViewControllerDisappear(viewController: viewController)
                }
            })
        _ = deinitDisposable.insert(disposable)
    }

    deinit {
        LeakDetector.instance.expectDeallocate(object: viewControllable.uiviewController, inTime: LeakDefaultExpectationTime.viewDisappear)
    }
}

 ViewableRouter VS Router 의 차이

ViewableRouter는 RIBs 노드에 ViewController가 포함되어 있을 경우,

Router는 RIBs 노드에 ViewController가 포함되어 있지 않을 경우

의 차이로 이해하고 있는데, 정확하진 않을수 있습니다! ㅎㅎ;;

 

ViewableRouter는 InteractorType, ViewControllerType을 Generic 형태로 받고, ViewableRouting 프로토콜을 준수합니다.

 

이런 배경지식을 가지고 SampleRouter의 예제 코드를 한줄씩 이해해 나가 봅시다.

 

A. Interactable protocol 정의

Router는 RIBs 노드들 간의 routing을 하는 역할을 하는데, 추후 Interactor를 다룬 포스팅에서 설명하겠지만 RIBs 구조에서 Interactor는 비즈니스 로직을 구현하는 역할을 합니다.

Interactor에서 비즈니스 로직을 수행하다가, 다른 RIBs 노드로의 routing이 필요한 경우

Interactor는 Router에 routing 콜을 요청합니다. Router는 ViewableRouting 이라는 프로토콜을 준수함으로써 Interactor의 라우팅 콜 요청을 수행할 준비를 합니다.

 

예제코드의 경우 ViewableRouting 프로토콜을 준수하는 SampleRouting 프로토콜은 SampleInteractor에 정의되어 있으며, SampleRouter 에 정의한 SampleInteractable protocol을 통해 SampleInteractor에 정의된 SampleRouting프로토콜을 Get 해옵니다. 말이 삥삥 돌아서 어지럽네요 간단히 하자면~

" Interactable protocol 정의 " 한다는 것은 Router가 Interactor의 라우팅 콜을 수행하기 위해, Interactor로부터 ViewableRouting프로토콜을 Get해오고,  Get해온 ViewableRouting 프로토콜의 위임자가 된다는 것입니다!

SampleRouter의 예제코드에서 하단에

interactor.router = self

이 코드를 하기 위해서 하는거라는 말입니다! ㅎㅎ

 

그렇다면 한가지 더 이해할게 남았습니다!!

Interactor로부터 ViewableRouting프로토콜을 Get해오기 위해서는~~?

SampleRouter에 정의한 SampleInteractable 프로토콜은 누가 준수해야 하나요?

→ SampleInteractor가 준수해야 합니다! ㅇㅋ?

 

B. ViewControllable protocol 정의

Interactable protocol을 정의하는 이유와 똑같이 이해하면 됩니다!

Interactable protocol은 Interactor의 라우팅 콜을 수행하기 위해서 였습니다.

그렇다면 ViewControllable protocol은 누구의 라우팅 콜을 수행하기 위해서????

→ ViewController의 라우팅 콜을 수행하기 위해서입니다!

그렇다면 마찬가지로 SampleViewControllable 프로토콜은 누가 준수해야 하나요?

→ SampleViewController가 준수해야 합니다!! ㅇㅋ?

 

나중에 포스팅 하게 될

" RIBs + ReactorKit을 활용한 RIBs 노드 中 Interactor & Reactor "

" RIBs + ReactorKit을 활용한 RIBs 노드 中 ViewController "

에서 SampleInteractor가 SampleInteractable 프로토콜을,

SampleViewController가 SampleViewControllable 프로토콜을 준수하는 예제코드를 확인해 보시면 될겁니다!

 

C. Router 클래스 구현

InteractorType, ViewControllerType을 Generic 형태로 받고, ViewableRouting 프로토콜을 준수하는 Router 클래스를 구현합니다.

 

이 예제의 경우 SampleInteractable, SampleViewControllable 을 Generic 형태로 받고 SampleRouting 프로토콜을 준수하는 SampleRouter 클래스를 구현합니다.

SampleRouter 클래스의 코드 설명은 생략합니다. (위에서 다 설명함!) 👍

 

다음번엔 " RIBs + ReactorKit을 활용한 RIBs 노드 中 Interactor & Reactor " 포스팅을 이어나갈 계획입니다! 😄