본문 바로가기
🍎 iOS

[Swift] MVVMC 자세히 알아보기 - 튜토리얼 2 (childCoordinator로 이동하기)

by 틴디 2022. 7. 11.
728x90
반응형

2022.07.10 - [🍎 iOS/Architecture Pattern] - [Swift] MVVMC 자세히 알아보기 - 튜토리얼 1

위 포스팅 후에 이어서 하는 포스팅입니다 🙌🏻

https://www.pexels.com/ko-kr/photo/12499889/

LandingCoordinator

AppCoordinator는 앱을 처음 실행했을 때 첫 화면을 어떤 화면으로 할지 담당하는 Coordinator입니다. 화면을 그리기 위해 필요한 데이터(dependency)를 준비하고 네트워킹을 위한 객체를 설정합니다. 

위 그림을 보면 AppCoordinator에서 Landing 화면을 보여줄 수도 있고, 자동 로그인이 되어 있다면 HomeCoordinator로 이동할 수 있습니다. 

 

우선 LandingCoordinator을 작성하겠습니다. 

import UIKit

class LandingCoordinator: Coordinator {
    var parentCoordinator: Coordinator?
    var childCoordinators = [Coordinator]()
    
    let navigationController: UINavigationController
    
    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }
    
}

LandingCoordinator는 AppCoordinator의 Child Coordinator 에요! 반대로 LandingCoordinator의 parentCoordinator는 AppCoordinator입니다. 이 관계를 사용해서 childCoordinator와 parentCoordinator에서 화면 전환을 할 수 있습니다. 

이니셜라이저를 통해 UINavigationController를 받습니다.

이제 AppCoordinator에서 LandingCoordinator로 화면을 전환할 수 있도록 코드를 작성해 줍시다!

import UIKit

class AppCoordinator: Coordinator {
    var parentCoordinator: Coordinator? = nil
    var childCoordinators = [Coordinator]()
    private let window: UIWindow?
    
    lazy var navigationController: UINavigationController = {
        let rootViewController = UIViewController()
        rootViewController.view.backgroundColor = .white
        let navigationController = UINavigationController(rootViewController: rootViewController)
        return navigationController
    }()
    
    init(window: UIWindow?) {
        self.window = window
    }
    
    func start() {
        guard let window = window else {
            return
        }
        window.rootViewController = navigationController
        window.makeKeyAndVisible()
    }
    
    // 1
    func goToLandingPage() {
        let landingCoordinator = LandingCoordinator(navigationController: navigationController)
        landingCoordinator.parentCoordinator = self
        addChildCoordinator(landingCoordinator)
        landingCoordinator.start()
    }
}

이전에 작성해 두었던 AppCoordinator코드에 하단에 goToLandingPage()를 추가해 줍니다. LandingCoordinator을 생성할 때 AppCoordinator의 navigationController을 전달해 줍니다. 같은 navigationController을 공유하고 화면 전환 하는데에 사용됩니다. 

landingCoordinator의 parentCoordinator는 AppCoordinator이기 때문에 Coordinator을 따르고 있는 AppCoordinator을 self로 전달합니다. 

그 후 AppCoordinator의 childCoordinator로 추가하리 위해 addChildCoordinatr()의 인자로 landingCoordinator을 전달합니다. 

LandingCoordinator 또한 Coordinator 프로토콜을 따르기 때문에 start() 함수를 아직 작성하지 않았지만 warring 없이 작성이 될거에요!

 

    func start() {
        guard let window = window else {
            return
        }
        window.rootViewController = navigationController
        window.makeKeyAndVisible()
        
        goToLandingPage()
    }

AppCoordinator에서 start() 에 마지막 한줄을 추가해 줍시다! goToLandingPage() 를 호출해서 AppCoordinator -> LandingCoordinator로 이동합니다.

 

LadingViewController

AppCoordinator에서 LandingCoordinator로 이동하면 LandingCoordinator의 start() 함수를 호출합니다. 이제 LandingCoordinator의 start() 부분을 작성해 줍시다. LanidngCoordinator의 첫 화면을 작성해 주기 위해 LandingViewController 파일을 추가해 주세요!

class LandingViewController: UIViewController {
    weak var landingViewModel: LandingViewModel?

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white
        let loginButton = UIButton(frame: CGRect(x: 0, y: 0, width: 150, height: 30))
        view.addSubview(loginButton)
        loginButton.center = view.center
        loginButton.setTitleColor(.black, for: .normal)
        loginButton.setTitle("로그인", for: .normal)
        
        let registerButton = UIButton()
        view.addSubview(registerButton)
        registerButton.center = view.center
        registerButton.frame = CGRect(x: loginButton.frame.origin.x, y: loginButton.frame.origin.y + loginButton.frame.size.height + 20, width: 150, height: 30)
        registerButton.setTitleColor(.black, for: .normal)
        registerButton.setTitle("회원가입", for: .normal)
    }

	override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationItem.hidesBackButton = true
    }
}

LandingViewController는 화면에 로그인과 회원가입 버튼을 배치합니다. 비즈니스 로직을 담당하기 위한 ViewModel 타입의 프로퍼티도 생성해 줍니다. LandingViewModel 파일도 생성해 줍니다. 

AppCoordinator의 UINavigationController에서 화면 전환이 이루어지고 있고 rootViewController에서 LandingViewController 화면이 올라오게 되어 백버튼이 나타납니다. 네비게이션바를 hidden처리해줘야 하는데 우선 백버튼만 가려놓겠습니다 🥲

class LandingViewModel {
    
}

현재 튜토리얼에서는 ViewModel과 Networking을 다루지 않아서 클래스만 생성해 주겠습니다!!

다시 LandingCoordinator로 돌아와서 LandingViewController에게 필요한 dependency인 viewModel을 생성하고 전달해 준 뒤 Landing화면으로 전환하도록 해주기 위해 start() 함수를 마저 작성합니다.

class LandingCoordinator: Coordinator {
    var parentCoordinator: Coordinator?
    var childCoordinators = [Coordinator]()
    
    let navigationController: UINavigationController
    // 1
    let landingViewController = LandingViewController()
    
    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }
 
    // 2
    func start() {
        let landingViewModel = LandingViewModel()
        landingViewController.landingViewModel = landingViewModel
        navigationController.pushViewController(landingViewController, animated: false)
    }
}

1. LandingViewController 를 생성해 줍니다.

2. LandingViewModel을 생성하고 landingViewController의 viewModel로 전달해 줍니다. 그 후 navigationController에 push 해줍니다. 

Coordinator의 역활인 화면전환과 dependency  설정을 해줄 수 있습니다!

 

코드를 실행하면 AppCoordinator에서 LandingCoordinator로 이동하면서 현재 화면에 LandingViewController가 나타나는 것을 확인할 수 있습니다. 

Landing과 관련된 화면이 여러개 일 수 있고 다양한 화면 전환이 일어날 수 있습니다. 이때 이를 처리하는 것이 LandingCoordinator의 역활입니다. 그리고 여기서 다시 childCoordinator 즉 새로운 Scene으로 이동할 수도 있는데요!

다음 포스팅에서는 랜딩 페이지에서 로그인과 회원가입으로 이동하는 것에 대해서 튜토리얼을 작성하고 start와 같이 작성해 주었던 finish에 대해 포스팅하겠습니다!!

728x90
반응형

댓글