관리 메뉴

김종권의 iOS 앱 개발 알아가기

[Architecture] Coordinator pattern, XCoordinator 프레임워크 [개념] 본문

Architecture (swift)

[Architecture] Coordinator pattern, XCoordinator 프레임워크 [개념]

jake-kim 2020. 10. 1. 16:32

Coordinator란

- 화면 전환하는 역할을 "Coordinator"라는 것에 부여

- viewModel에서 trigger를 통해 화면전환을 요청

Coordinator의 이점

  • 화면간의 연결이 쉬움
  • DI이 쉬워짐 (의존성 주입을 통해 소크 코드 내부가 아닌 외부에 정의하도록 하여 의존성을 분리시키는 것)
  • ViewController에서 네비게이션 코드 삭제

 XCoordinator사용

  • XCoordinator프레임워크 import
// pod install
pod 'XCoordinator'

// import
import XCoordinator

 

  • Coordinator가 될 클래스 정의
    • enum을 사용하여 화면에 전달될 인수(dependencies)를 함께 전달
    • NavigiationCoorinator<enum정의한 타입> 클래스 작성
    • prepareTransition(for:)함수 구현
//
//  UserListCoordinator.swift
//  Wise
//
//  Created by 김종권 on 2020/10/01.
//  Copyright © 2020 jongkwon kim. All rights reserved.
//

import Foundation
import XCoordinator

enum UserListRoute: Route {
    case home(_ email: String)
    case selectOption
    case option
    case list
}

class UserListCoordinator: NavigationCoordinator<UserListRoute> {
    init() {
        super.init(initialRoute: .home("email@a.com"))
    }

    override func prepareTransition(for route: UserListRoute) -> NavigationTransition {
    
    	rootViewController.setNavigationBarHidden(true, animated: false) // navigationBar를 숨기는 코드
    
        switch route {
        case .home(let email):
        	// email은 ViewModel에서 정보를 넘길 때 사용 될 것, router.trigger(.home(email: "abc@.a.com"))
            let dependencies = HomeVM.Dependencies()
            let vm = HomeVM(router: unownedRouter, dependencies: dependencies)
            let vc = HomeVC.instantiate(viewModel: vm)
            return .push(vc)

        case .option:
            let dependencies = OptionVM.Dependencies()
            let vm = OptionVM(dependencies: dependencies)
            let vc = OptionVC.instantiate(viewModel: vm)
            return .push(vc)

        case .selectOption:
            let dependencies = SelectOptionVM.Dependencies()
            let vm = SelectOptionVM(dependencies: dependencies)
            let vc = SelectOptionVC.instantiate(viewModel: vm)
            return .push(vc)

        case .list:
            let dependencies = ListVM.Dependencies()
            let vm = ListVM(dependencies: dependencies)
            let vc = ListVC.instantiate(viewModel: vm)
            return .present(vc, animation: .default)

        }
    }
}
  • 첫 화면 home으로 이동하게끔, SceneDelegate에 router의 root초기화
    • router를 변수로 선언해놓고, 이를 scene함수에서 사용
//
//  SceneDelegate.swift
//  Wise
//
//  Created by 김종권 on 2020/09/21.
//  Copyright © 2020 jongkwon kim. All rights reserved.
//

import UIKit
import XCoordinator

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    var router = UserListCoordinator().strongRouter

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead)

        if let scene = scene as? UIWindowScene {
            window = UIWindow(windowScene: scene)
            router.setRoot(for: window!)
            window?.makeKeyAndVisible()
        }
    }
    ...
  • HomeVM에 다음과 같은 코드가 존재: ViewModel에서는 항상 router와 dependencies를 init에서 사용한 후, router.trigger(.)을 통해 화면전환
//
//  HomeVM.swift
//  WiseWord
//
//  Created by 김종권 on 2020/09/16.
//  Copyright © 2020 jongkwon kim. All rights reserved.
//

import Foundation
import UIKit
import RxSwift
import RxCocoa
import UserNotifications
import XCoordinator

class HomeVM {

    let bag = DisposeBag()

    // MARK: - Dependencies

    struct Dependencies {
    }

    // MARK: - Properties

    private let router: UnownedRouter<UserListRoute>
    let dependencies: Dependencies

    // MARK: - Init

    init(router: UnownedRouter<UserListRoute>, dependencies: Dependencies) {
        self.dependencies = dependencies
        self.router = router
    }

    func routeToOption() {
        router.trigger(.option)
    }
}

* XCoordinator 응용, 딥링크 처리: ios-development.tistory.com/189

 

참고: github.com/quickbirdstudios/XCoordinator

Comments