티스토리 뷰

728x90
반응형

Coordinator pattern 을 알아보자

참고

위의 글을 참고해서 coordinator pattern 을 실습해보았다.

초기설정

👊 SceneDelegate.swift 삭제

  1. App Delegate에서 Scene delegate 메서드 삭제

1

  1. Scene delegate file 삭제

2

  1. Info.plist에서 UIApplicationSceneManifest 삭제

3

  1. AppDelegate에 var window:UIWindow? 추가
  • Scene delegate가 추가된 iOS 13이후에는 위 과정을 거치지 않으면 Coordinator를 이용한 화면전환이 정상적으로 동작하지 않습니다.

👊 첫 화면을 실행해 보자

  • Coordinator.swift
import Foundation
import UIKit

protocol  Coordinator {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }

    func start()
}
  • MainCoordinator.swfit

Coordinator 프로토콜을 채택해서 화면전환을 설정

import Foundation
import UIKit

class MainCoordinator: NSObject, Coordinator {

    var childCoordinators = [Coordinator]()
    var nav: UINavigationController

    init(navigationController: UINavigationController) {
        self.nav = navigationController
    }

    // ✅ 앱이 보여질 때 처음 화면
    func start() {
        // ✅ 뷰컨트롤러 인스턴스 커스텀 메서드 
        let vc = ViewController.instantiate()
        vc.coordinator = self
        nav.pushViewController(vc, animated: false)
    }
}
  • Storyboarded.swift

스토리보드에 접근해서 뷰컨트롤러의 이름을 identifier 로 가진 뷰컨트롤러를 손쉽게 인스턴스화하기 위한 instantiate() 메서드 구현.

import Foundation

import UIKit

protocol Storyboarded {
    static func instantiate() -> Self
}

extension Storyboarded where Self: UIViewController {
    static func instantiate() -> Self {
        // ✅ ex) "CoordinatorPractice(프로젝트 이름).ViewController"
        let fullName = NSStringFromClass(self)

        // ✅ .을 기준으로 split해 "ViewController"만 추출
        let className = fullName.components(separatedBy: ".")[1]

        // ✅ Bundle.main에서 Main.storyboard 가져오기
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

        // ✅storyboard에 className을 identifier로 가지고 있는 ViewController 인스턴스화
        return storyboard.instantiateViewController(withIdentifier: className) as! Self
    }
}

4

다음과 같이 id 값을 설정해주어야 한다.

  • ViewController.swift
import UIKit

class ViewController: UIViewController, Storyboarded {

    // ✅ MainCoorinator 추가
    weak var coordinator: MainCoordinator?

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  • AppDelegate.swift

SeneDelegate.swift 를 삭제한 후 첫 화면을 실행하기 위한 코드

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var coordinator: MainCoordinator?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let navigationContorller = UINavigationController()
        coordinator = MainCoordinator(navigationController: navigationContorller)
        coordinator?.start()

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = navigationContorller
        // ✅
        window?.makeKeyAndVisible()

        return true
    }
}

makeKeyAndVisible

  • window 보여주기 및 keyWindow 설정 메서드.
  • keyWindow: 키보드 및 터치 이벤트가 아닌 이벤트도 받을 수 있도록 등록
  • window의 rootViewController를 위에서 세팅해주고 makeKeyAndVisible() 부르면 마침내 지정한 rootViewController가 상호작용을 받는 현재 화면으로 세팅 완료

참고 :

[iOS - swift] UIWindow, makeKeyAndVisible()

👊 화면 전환을 해보자

  • Main.storyboard

스크린샷 2021-08-21 오후 9 49 26

추가로 LeftViewController 와 RightViewController 를 만들어주고 ViewController 와 동일하게 weak var coordinator: MainCoordinator? 추가하고 Storyboarded 프로토콜을 채택해준다.

  • MainCoordinator.swift
class MainCoordinator: NSObject, Coordinator {

    // ...

    // ✅ 추가 화면 전환
    func pushToLeftVC() {
        let vc = LeftViewController.instantiate()
        vc.coordinator = self
        // ✅ push 되는 애니메이션 여부 true 설정
        nav.pushViewController(vc, animated: true)
    }

    func pushToRightVC() {
        let vc = RightViewController.instantiate()
        vc.coordinator = self
        nav.pushViewController(vc, animated: true)
    }
}

👊 데이터 전달

그렇다면 coordinator 패턴에서는 어떻게 화면전환 시 데이터를 전달해줄까?

비슷하다. MainCoordinator 의 화면전환 함수에 파라미터를 만들어준다. 그 후 뷰컨트롤러에서 호출할 때 파라미터를 전달받아서 화면전환할 뷰컨트롤러의 인스턴스에 넣어주면 된다.

  • MainCoordinator.swift
class MainCoordinator: NSObject, Coordinator {

// ...

    func pushToLeftVC(string: String) {
        let vc = LeftViewController.instantiate()
        vc.coordinator = self

        // ✅ 데이터 전달
        vc.string = string
        nav.pushViewController(vc, animated: true)
    }

// ...

}
  • LeftViewController.swift
import UIKit

class LeftViewController: UIViewController, Storyboarded {

    // ✅ 데이터를 받을 옵셔널 변수
    var string: String?

    weak var coordinator: MainCoordinator?

    override func viewDidLoad() {
        super.viewDidLoad()

        // ✅ 전달된 데이터 확인
        if let string = string {
            print(string)
        }
    }
}

 

여기서 만들어두고 사용하지 않았던 child coordinator 에 대해서 다음글을 통해 알아보자

 

iOS) Coordinator pattern 적용해보자- Advanced

간단한 예제로 살펴보는 iOS Design/Architecture Pattern: Coordinator - Advanced 이번 실습 역시 위의 글을 참고했다. 👊 parent coordinator & child coordinator Basic 에서는 한개의 Coordinator 만 사용했..

gyuios.tistory.com

 

728x90
반응형
댓글
최근에 올라온 글
최근에 달린 댓글
글 보관함
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
링크
Total
Today
Yesterday