protocol Coordinator: AnyObject {
var childCoordinators: [Coordinator] { get set }
var navigationController: UINavigationController { get set }
var finishFlow: (() -> Void)? { get set }
func start()
}
childCoordinators:
자신의 하위 Coordinator 들이 들어갈 배열
navigationController:
자신의 ViewController 들을 보여주기 위함.
finishFlow:
자신의 Coordinator 가 끝났다는 것을 상위에 알려주기 위함
이 이벤트를 상위에서 받으면, childCoordinators 에서 해당 coordinator 제거
start:
자신의 Coordinator 초기 설정
해당 Coordinator 가 제어권을 가져가게 하기 위함
여기서 ViewController 를 생성하여 navigationController 를 구성
SceneDelegate 에서 연결
메모리에서 해제되는 것을 방지하기 위해, SceneDelegate 가 RootCoordinator(모든 Coordinator 의 최상단) 를 프로퍼티로 가진다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var coordinator: RootCoordinator?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
let coordinator = RootCoordinator()
coordinator.start()
self.coordinator = coordinator
window.rootViewController = coordinator.getRootViewController()
window.makeKeyAndVisible()
self.window = window
}
ViewController 에서 화면전환 이벤트 처리
2가지 방법이 있다:
ViewController 가 Coordinator 를 알고있고, 직접 화면전환 요청
ViewController 가 Coordinator 를 모르고, 간접적 화면전환 요청
먼저, 1️⃣ ViewController 가 Coordinator 에게 직접 화면전환을 요청하는 방법이다. ViewController 은 coordinator 인스턴스를 내부에 가지고 있다:
2️⃣ ViewController 에서 간접적으로 화면요청을 하는 방법:
Coordinator 가 ViewController 를 생성하고 있으므로 delegate 패턴(클로저) 를 통해 ViewController 가 보낸 이벤트를 Coordinator 가 감지할 수도 있다. 이때는 coordinator 를 직접 알 필요없다.
들어가며…
ViewController 는 View+Controller 의 역할을 하므로, 태생부터(?) 과중한 업무를 하게끔 되어있다. ViewController 가 Massive 하는데 영향을 주는 것들 중 하나는 화면 전환이라고 할 수 있다.
아래 코드는 버튼을 터치했을때
문제점: 유지보수의 어려움
어느 화면을 이동하느냐를 알기위해서 ViewController 의 모든 코드를 봐야 한다. 많은 코드가 있는 ViewController 에서 화면 전환 코드만 찾아내는 것은 작업시간을 늘릴여지가 다분하다.
또한 이동할 ViewController 의 인스턴스 생성을 함수 내부에서 하고 있다. 이는 화면간 관계를 파악하기에 어려워 지는 단점이 있다.
Coordinator 란?
예)
Coordinator 를 적용하면, 화면생성과 화면이동(Routing) 코드를 ViewController 부터 분리해낼 수 있다. ViewController 는 단지 Coordinator 에게 요청만 하면 된다:
구현
Coordinator Protocol 정의
childCoordinators
:navigationController
:finishFlow
:start
:SceneDelegate 에서 연결
메모리에서 해제되는 것을 방지하기 위해, SceneDelegate 가 RootCoordinator(모든 Coordinator 의 최상단) 를 프로퍼티로 가진다.
ViewController 에서 화면전환 이벤트 처리
2가지 방법이 있다:
ViewController 가 Coordinator 를 모르고, 간접적 화면전환 요청
2️⃣ ViewController 에서 간접적으로 화면요청을 하는 방법: Coordinator 가 ViewController 를 생성하고 있으므로 delegate 패턴(클로저) 를 통해 ViewController 가 보낸 이벤트를 Coordinator 가 감지할 수도 있다. 이때는 coordinator 를 직접 알 필요없다.
자식 Coordinator 의 흐름이 끝났을때 처리
ViewController 에서 이벤트를 보낸다
Coordinator 에서 이를 감지하여 자신의 실행흐름을 끝낼것인지를 결정한다:
finishFlow?()
호출부모 코디네이터에서 이를 감지하여, 자신의 childCoordinator 배열에서 해당 child Coordinator 를 제거