[iOS] View 전환 시 강한 결합(Strong Coupling) 문제와 Coordinator 패턴을 활용한 해결 방법
개인 프로젝트에서 한 ViewController에서 다른 ViewController로 이동할 때, 직접 객체를 생성하고 메서드를 호출하는 방식을 사용했다.
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func navigateToNextView(_ sender: UIButton) {
let secondVC = SecondViewController()
navigationController?.pushViewController(secondVC, animated: true)
}
}
이 방식에는 여러 문제가 있었다.
ViewController 간의 직접적인 의존성 발생:
FirstViewController
가SecondViewController
의 구체적인 구현을 알아야 함.유지보수 어려움: ViewController 간의 이동 방식이 변경될 경우 모든 호출 코드를 수정해야 함.
테스트 어려움:
FirstViewController
가SecondViewController
를 직접 참조하므로, 단위 테스트 작성이 어려워짐.
검색을 통해 이러한 문제들을 Coordinator 패턴을 도입하여 해결할 수 있었다.
Coordinator 패턴이란?
ViewController 간의 이동을 관리하는 별도의 객체(Coordinator)를 두어, ViewController 간 결합도를 낮추는 구조적 패턴
Coordinator의 핵심 원칙
ViewController는 화면 이동을 직접적으로 처리하지 않는다.
Coordinator가 화면 전환을 관리하며, ViewController는 Coordinator에게 이동을 요청한다.
화면 이동 로직을 ViewController에서 분리하여 유지보수성을 높인다.
Coordinator 패턴 적용하기
Coordinator 프로토콜 정의
Coordinator는 화면 이동을 담당하는 객체이므로, 이를 추상화한 프로토콜을 정의한다.
protocol Coordinator {
func start()
}
MainCoordinator 구현
앱에서 화면 이동을 관리하는 MainCoordinator를 생성하여, ViewController 간의 네비게이션을 담당하도록 한다.
class MainCoordinator: Coordinator {
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let firstVC = FirstViewController()
firstVC.coordinator = self
navigationController.pushViewController(firstVC, animated: false)
}
func showSecondView() {
let secondVC = SecondViewController()
navigationController.pushViewController(secondVC, animated: true)
}
}
ViewController에서 Coordinator 사용하기
FirstViewController
에서 Coordinator
를 사용하도록 변경한다.
class FirstViewController: UIViewController {
var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func navigateToNextView(_ sender: UIButton) {
coordinator?.showSecondView()
}
}
AppDelegate 또는 SceneDelegate에서 Coordinator 초기화
앱이 실행될 때 Coordinator
를 초기화하고, UINavigationController
에 연결해야 한다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var coordinator: MainCoordinator?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let navController = UINavigationController()
coordinator = MainCoordinator(navigationController: navController)
coordinator?.start()
window = UIWindow(windowScene: windowScene)
window?.rootViewController = navController
window?.makeKeyAndVisible()
}
}