08 May 2020

Extension

RIB에서 ViewControllable 프로토콜을 이용하여 Router에서 ViewControllable에게 어떤 것이 필요한지를 정의하고, ViewControllable를 만족하는 ViewController는 해당 기능을 구현합니다.

protocol MainViewControllable: ViewControllable {
  func present(viewController: ViewControllable)
  func dismiss(viewController: ViewControllable)
}

class MainViewController: UIViewController, MainViewControllable {
  func present(viewController: ViewControllable) {
  	...
  }

  func dismiss(viewController: ViewControllable) {
  	...
  }
}

Router에서는 ViewController에게 요청하는 것들은 대부분 Present, Push, Dismiss, Pop 같은 요청들이 많습니다. 따라서 이러한 것들을 매번 구현하는 것 보다는 공통으로 만들어 사용하는 것이 깔끔합니다.

그래서 ViewControllable을 따르는 NavigateViewControllable를 정의하고, NavigateViewControllable는 대부분의 공통 코드인 Present, Push, Dismiss, Pop을 선언하고, Extension에서 구현합니다.

protocol NavigateViewControllable: ViewControllable {
  func presentViewController(viewController: ViewControllable)
  func presentNavigationViewController(root: ViewControllable)
  func dismissViewController(viewController: ViewControllable)
  func pushViewController(viewController: ViewControllable)
  func popViewController(viewController: ViewControllable)
}

extension NavigateViewControllable {
  func presentViewController(viewController: ViewControllable) {
    uiviewController.present(viewController.uiviewController, animated: true, completion: nil)
  }
  func presentNavigationViewController(root: ViewControllable) {
    let navi = UINavigationController(rootViewController: root.uiviewController)
    uiviewController.present(navi, animated: true, completion: nil)
  }
  func dismissViewController(viewController: ViewControllable) {
    viewController.uiviewController.dismiss(animated: true, completion: nil)
  }
  func pushViewController(viewController: ViewControllable) {
    uiviewController.navigationController?.pushViewController(viewController.uiviewController, animated: true)
  }
  func popViewController(viewController: ViewControllable) {
    uiviewController.navigationController?.popToViewController(uiviewController, animated: true)
  }
}

Wrapper

ViewControllable는 UIViewController를 속성으로 가지는 Protocol로, 아주 간단하게 되어 있습니다. 그리고 ViewControllable가 특정 UIViewController를 따르도록 하면 더 쉽게 사용할 수 있습니다.

하지만 ViewControllable이 특정 UIViewContoller에 사용이 불가피한 경우에는 일반 class 타입이 ViewControllable를 따르도록 하고, UIViewController 객체를 주입하는 방식으로 할 수 있습니다.

protocol MainViewControllable: ViewControllable {}

final class MainViewControllerWrapper: MainViewControllable {
  let uiviewController: UIViewController

  init(uiviewController: UIViewController) {
  	self.uiviewController = uiviewController
  }
}