Design Patterns

Coordinator Pattern 연습 1

JoonSwift 2022. 1. 25. 00:01

Coordinator Pattern을 연습해 보았습니다.

 

우선 Coordinator 라는 영어 단어의 의미를 생각해 보았습니다. 가장 눈에 들어왔던 의미는 '진행자'였습니다. View Controller들 사이의 흐름에 대한 구조를 구성하기 위한 즉, "View Controller들 사이에 진행자인 Coordinator가 View Controller의 흐름을 컨트롤 해주는구나!" 정도로 이해중입니다. 

 

Raywenderlich의 Coordinator Pattern 자료에는 Router라는 녀석도 함께 나오는데 간단하게 정리해보자면, 

  • Router : Router는 어떤 View Controller를 보여줄지 모르지만, View Controller를 어떻게(How) 보여줄지에 대한 정의를 하는 녀석입니다. 
  • Coordinator : Coordinator는 View Controller를 어떻게 정의할지, 그리고 어떤 순서로 View Controller를 보여줄지를 알고 있는 녀석입니다. 

이 둘을 잘 합치면, Coordinator가 Router에게 어떤 View Controller를 보여줄지를 제공하면, Router는 해당 View Controller를 어떻게 보여주는지는 Router의 역할이 되는것입니다.

 

코드

 

프로젝트는 간단하게 NewsAPI에서 News를 가져와 해당 뉴스를 선택하면 그 뉴스의 Content를 보여주는 프로젝트입니다. 

 

프로젝트의 구조는 대략적으로 위와 같습니다. 우선 프로젝트의 흐름을 생각해 보겠습니다. NewsHomeViewController가 있고, NewsDetailViewController가 하나의 흐름입니다. 

 

NewsHomeViewController에서 뉴스를 선택하면 NewsDetailViewController가 보여집니다. 해당 로직을 원래는 NewsHomeViewController의 didSelectRowAt같은 메서드에서 구현을 했었습니다.

//NewsHomeViewController.swift

//didSelectRowAt 메서드 내부
let viewController = NewsDetailViewController()
navigationController.pushViewController(viewController, ... )

 

이런식으로 말이죠. 하지만 Coordinator Pattern에서는 이 기능은 Coordinator의 몫입니다. View Controller를 생성하고, 다음에는 어떤 View Controller가 보여질지 Router에게 알려줍니다. 

extension NewsCoordinator: NewsHomeViewControllerDelegate {
  func didSelectNews(_ viewController: UIViewController, news: News) {
    let viewController = NewsDetailViewController(news: news)
    
    router.present(
      viewController,
      animated: true,
      onDismissed: nil
    )
  }
}

 

해당 부분은 News를 선택했을 때 NewsDetailViewController를 보여주는 로직입니다. 즉, Coordinator Pattern을 사용하면, 같은 흐름에 있는 View Controller들이라도 서로 모르는 사이가 된다는 것입니다. 

 

이제 Router의 present( ... ) 메서드에 viewController를 전달했습니다. Router쪽 코드를 보겠습니다. 

 

Router는 위에도 설명했지만, View Controller를 어떻게 보여줄지를 구현해 놓은 부분입니다. 이 프로젝트의 흐름에서는 NavigationController가 필요할 것이고, push, pop을 하며 View Controller를 보여주고 사라지게 만들어 주어야 합니다.

 

따라서 위의 router.present( ... ) 메서드가 하는일은 push 입니다. 코드를 보겠습니다.

// SceneDelegateRouter.swift

func present(
  _ viewController: UIViewController,
  animated: Bool,
  onDismissed: (() -> Void)?) {
    onDismissForViewController[viewController] = onDismissed
    navigationController.pushViewController(
      viewController,
      animated: animated
    )
}

onDismissForViewController는 View Controller가 사라질 때 실행될 클로저를 모아둔 딕셔너리입니다. 따라서 보여질 View Controller의 onDismissed 클로저를 저장하고, navigationController.pushViewController( ... ) 메서드를 실행합니다. 

 

다음은 dismiss 메서드를 살펴보겠습니다.

// SceneDelegateRouter.swift

func dismiss(animated: Bool) {
  guard let routerRootViewController = navigationController.viewControllers.first else {
    navigationController.popToRootViewController(animated: true)
    return
  }
  performOnDismissed(for: routerRootViewController)
  navigationController.popToViewController(
    routerRootViewController,
    animated: animated
  )
}

dismiss 는 rootViewController의 여부를 체크하여, popToRootViewController(...) 메서드를 실행시키거나, rootViewController의 onDismissed 클로저를 실행시키고, popToViewController( ... ) 메서드를 통해 rootViewController로 이동하게 구현해주었습니다. 

 

생각 / 고민

Coordinator Pattern에 대해 검색해보니 수많은 자료들이 나왔다. NSSpain의 발표자료부터 Github의 많은 예제, Raywenderlich, ... 수많은 자료 중 Raywenderlich의 자료를 먼저 보았고, 자료를 보며 내가 이해한 대로 간단하게 프로젝트를 만들어보았다. 다른 자료들도 더 찾아보며 보완해가야겠다고 생각했다.

아직까지 이점을 정확하게 모르겠다. 하나의 흐름에 있는 View Controller 끼리 서로 모른다는 것은 알겠지만, 이것의 이점이 무엇인지에 대한 이해가 필요할 것 같고, Coordinator에 View Controller들의 Protocol을 계속 채택하다보면 Coordinator의 크기가 정말 커지지 않을까? 라는 생각도 들었다. 

계속 공부해봐야겠다!

 

참고 자료

https://www.raywenderlich.com/books/design-patterns-by-tutorials

 

Design Patterns by Tutorials

<p>Learn design patterns with Swift!</p> <p>Design patterns are incredibly useful, no matter what language or platform you develop for. Using the right pattern for the right job can save you time, create less maintenance work for your team and ultimately l

www.raywenderlich.com

 

'Design Patterns' 카테고리의 다른 글

Design Pattern, RxSwift ) RxFlow 맛보기 - 1  (0) 2022.07.19
Iterator Pattern?!  (0) 2022.02.04
느낌대로 만들어본 TabBar, Navigation Coordinator  (0) 2022.01.27
Observer Pattern  (0) 2021.06.03