Skip to content

Coordinator

Jinwon Choi edited this page Mar 19, 2025 · 1 revision

ViewController 이용한 화면 전환에서 발생하는 여러 문제들을 줄이기 위한 방법

  • ViewController에서 pop, push 등을 이용한 화면 전환까지 담당하는 많은 책임을 가지고 있다.
  • 커진 VC에서 화면 전환 로직만을 찾아 확인하고 수정하기 번거롭다.
  • VC에서 처리하면서 결합도가 너무 높다.
  • 화면 전환을 위한 VC마다 새롭게 인스턴스를 생성해야 전환시킬 수 있다.

Coordinator 패턴

화면 전환 로직을 관리하는 Coordinator 객체를 만들어 ViewController가 아닌 Coordinator가 해당 역할을 수행하도록 하는 구조이다. Coordinator는 앱의 주요 흐름을 컨트롤하며, 각 부분에 따라 여러 Coordinator가 존재할 수 있다.

Coordinator1

특징

  • 단일 책임 원칙
    • 화면 전환 역할을 하는 객체인 Coordinator의 존재로, VC은 UI에만 집중할 수 있어진다.
  • 재사용성
    • Coordinator는 특정 플로우데 따라 여러개가 있을 수 있는데, 동일한 플로우가 필요하다면 여러 곳에서 재사용 가능하다.
  • 화면 전환 로직 변경
    • Coordinator에서 화면 전환과 네비게이션을 관리하기 때문에 로직 수정이 더 간단하다.
  • 순환 참조
    • Coordinator의 개수가 많아질수록 순환 참조의 위험성이 발생한다.
    • 배열에 Coordinator를 저장하고, 필요 없는 경우 해제하는 방식으로 방지할 수 있다.
  • 확장성
    • 복잡한 화면 전환 플로우를 가진 대규모 앱일수록 적합하다.

기본 구성

  • Coordinator 프로토콜
    • 모든 코디네이터는 공통된 메서드를 따르기 위해서 코디네이터 프로토콜을 채택한다.
  • App Coordinator
    • 앱의 공통 네비게이션 기능을 제공하며, 주로 자식 코디네이터를 관리하거나 현재 상태를 유지한다.
  • 각각의 Coordinator
    • 특정 흐름을 담당하는 코디네이터(위에서 말한 자식 코드네이터)로, 각각의 흐름을 관리하고 VC과의 네비게이션을 수행한다.
  • Delegate 패턴 / Closure
    • 상위 코디네이터와 하위 코디네이터가 서로 상호작용할때 주로 델리게이트나 클로저로 상호작용한다.
    • 델리게이트와 클로저로 상호작용 하기 때문에 코디네이터를 독립적인 모듈로 유지할 수 있다.

플로우

  • 기본 화면 전환

Coordinator2

  • Coordinator 화면 전환

    Coordinator 자체가 화면 전환 객체이기 때문에, 화면끼리의 전환 로직이 필요한 것이 아니라 Coordinator와 연결되어 화면 전환을 요청하기만 하면 된다.

Coordinator3

사용

  1. Coordinator 프로토콜
protocol Coordinator {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }
    
    func start()
}
  • childCoordinators : 하위 Coordinator 가 들어갈 배열
  • navigationController : 자신 ViewController들을 보여줄 역할
  • start() : 해당 Coordinator가 관리하는 화면 표시하는 메서드
  1. AppCoordinator - 코디네이터의 최상위
class AppCoordinator: Coordinator {
    var childCoordinators = [Coordinator]()
    var navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        let authCoordinator = AuthCoordinator(navigationController: navigationController)
        authCoordinator.parentCoordinator = self
        childCoordinators.append(authCoordinator)
        authCoordinator.start()
    }

    func didFinishAuth() {
		    // 회원가입 끝났으니 로그인 화면으로 넘어가기
        let loginCoordinator = LoginCoordinator(navigationController: navigationController)
        childCoordinators.append(loginCoordinator)
        loginCoordinator.start()
    }
}
  1. AuthCoordinator
class AuthCoordinator: Coordinator {
    var childCoordinators = [Coordinator]()
    var navigationController: UINavigationController
    weak var parentCoordinator: AppCoordinator?

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        let authViewController = AuthViewController()
        authViewController.coordinator = self
        navigationController.pushViewController(authViewController, animated: true)
    }

    func didFinishAuth() {
        parentCoordinator?.didFinishAuth()
    }
}
  1. AuthViewController
class AuthViewController: UIViewController {
    weak var coordinator: AuthCoordinator?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        // 회원가입 UI 설정
    }

    func authSuccessButtonTapped() {
        // 회원가입 로직
        coordinator?.didFinishLogin()
    }
}

참고

https://velog.io/@kimscastle/iOS-Coordinator-Pattern-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

https://mini-min-dev.tistory.com/264

Welcome to SniffMEET Wiki!

💬 허거덩 팀 규칙

개발 일지

구조
NI, MPC
프로파일링
리팩토링/리디자인
테스트
Supabase

기술 공유

회의록

회의록

트러블 슈팅

발표

💬 허거덩 팀 규칙

Clone this wiki locally