Trouble Shooting

[Swift UIKit]present의 주체 (modal을 표시하는건 누구의 역할일까?)

Kim Roks 2025. 1. 8. 19:14

코디네이터 패턴을 학습하고 구현하는 과정에서 여러 시행착오를 겪었다.
그 중에서도 특히 present와 dismiss의 주체가 누구인지에 대해 고민했다.

내가 구현한 코디네이터 프로토콜은 아래와 같이 navigationController를 가지고 있었는데,


import UIKit  

public protocol Coordinator: AnyObject {  
    var parentCoordinator: Coordinator? { get set }  
    var childCoordinators: \[Coordinator\] { get set }  
    //이거  
    var navigationController: UINavigationController { get set }  

    func start()  
    func didFinish()  
}  

이전까지 진행했던 프로젝트들은 화면 이동이 많지 않아, 크게 신경쓰지 않았던 부분인데

화면 이동이라고 하면 모달 방식으로 띄우면 present 닫으면 dismiss를 하고

네비게이션 스택을 쌓으면서 이동하면 push, pop을 사용한다 정도로 이해를 하고 있었다.

하지만 이번 프로젝트를 진행하며 화면 이동에 대해 조금 더 심도 있는 고민을 하게 된 계기가 있었는데

생소했던 코디네이터 패턴을 사용하며 가지고 있는

navigation Controller가 화면 이동을 하도록 만든 부분인데(패턴의 기본 생김새에 생각이 매몰됐다.)

이때 모달 방식의 present 또한 navigation Contoller가 담당했었다.

이는 사실 겉보기에 문제는 없다.
navigationControllerViewController서브클래스니까.

하지만 위 사진처럼 내 리뷰어이자 친한친구가 내게 해준 말이 많은 생각을 하게끔 만들었는데

모달 방식은 화면 이동시 navigation의 스택을 쌓는 방식이 아니며,

네비게이션 컨트롤러의 특성이 필요해서 구현한게 아니라면 조금 더 생각할 여지가 있다.

해당 방식 또한 의도에 따라 사용될 수 있겠지만 네비게이션”에서만” present가 가능한 지금의 코드는 의도에 벗어난다는 이야기다.

결론

ViewController를 주체로 사용하는 경우

개별 ViewController 간의 전환: presentdismiss는 주로 한 개의 ViewController가 다른 ViewController를 모달 방식으로 표시할 때 사용됨. 이 경우, 주체는 모달을 표시하는 현재의 ViewController가 된다. 이 방식은 독립적인 화면 전환에 적합하며, 화면 사이의 강한 연결이 필요하지 않을 때 사용.

UINavigationController를 주체로 사용하는 경우

내비게이션 스택 관리: UINavigationController는 여러 ViewController를 내비게이션 스택에 푸시(push) 또는 팝(pop)하는 데 사용된다. 이 경우, presentdismiss 대신 pushViewController:animated:popViewController:animated: 같은 메서드를 사용한다다. NavigationController는 일련의 화면이 계층적으로 관련되어 있을 때 적합할것.

그래서 결국 present의 주체가 누가 될것이냐,

앱의 구조와 해당화면 전환의 목적에 따라 달라질것이다.

하지만, 이번 리뷰를 통해 느낀점은 결국 코드를 작성하고 동작을 구현하는것은

‘단순히 구현했다’를 넘어서 항상 의도에 맞는 동작을 정의해야한다는것이다.