Skip to content

Conversation

@Rudy-009
Copy link
Contributor

@Rudy-009 Rudy-009 commented Dec 29, 2025

✅ Check List

  • 팀원 전원의 Approve를 받은 후 머지해주세요.
  • 변경 사항은 500줄 이내로 유지해주세요.
  • Approve된 PR은 Assigner가 직접 머지해주세요.
  • 수정 요청이 있다면 반영 후 다시 push해주세요.

📌 Related Issue


📎 Work Description

문제 정의

1. 루트뷰 전환의 관심사 분리가 필요하다.

  1. 로그인, 회원가입, 탭 (메인), 인터넷 연결 끊김(개인 예측), 강제 업데이트(개인 예측) 등의 많은 루트 뷰가 예상됩니다. 사전에 루트 뷰 전환을 염두하지 않으면, 추후에 뷰 컨트롤러가 매우 복잡해질 수 있습니다.
  2. 알림 뷰 : 알림 TableView 의 Cell의 상태에 따라 이동하는 TabBar 가 달라집니다. 알람 뷰는 어떤 한 뷰에서도 접근이 가능해야 하기에 (상단에 알림이 뜨면, 알림 뷰가 push 되어야 함) 단순하게, 접근하면 매우 복잡하게 구현해야할 수 있습니다.

만약, 로그인 성공 이후에 NavigationStack 으로 TabBar를 push 한다면, 불필요한 로그인 화면이 메모리에 올라가게 되며 이는 메모리를 효율적으로 사용하지 못하게 됩니다.

해결 방법

2. Factory Pattern

  • 관심사 분리: ViewController는 본인이 다음에 어디로 가야 하는지 구체적인 클래스명을 알 필요가 없습니다.

  • 유연성: 나중에 로그인 화면이 LoginVC에서 SocialLoginVC로 바뀌어도 Factory 코드만 수정하면 됩니다.

  • 메모리 관리: rootViewController를 통째로 갈아 끼우기 때문에 이전 화면들이 메모리에서 깔끔하게 해제됩니다.

3. 코드 설명 (화면 객체 생성 AppSceneFactory)

enum SceneType {
    case login
    case signup
    case main
}

protocol SceneFactory {
    func makeScene(for type: SceneType) -> UIViewController
}

final class AppSceneFactory: SceneFactory {
    func makeScene(for type: SceneType) -> UIViewController {
        switch type {
        case .login:
            let loginVC = LoginViewController()
            return UINavigationController(rootViewController: loginVC)
        case .signup:
            let signUpVC = SignUpViewController()
            return UINavigationController(rootViewController: signUpVC)
        case .main:
            let mainVC = TabBarController()
            return UINavigationController(rootViewController: mainVC)
        }
    }
}

'AppSceneFactory' : type 기반으로 뷰 컨트롤러를 생성합니다.

확장 가능성 : 연관 타입 (Associated type)을 이용하여 객체 주입이 가능해집니다.

enum이 아닌 SceneFactory 프로토콜의 함수를 추가, 삭제하고 매개변수를 이용해서 객체 주입을 받는 방향도 있습니다. (앱잼 때 합의해서 결정하면 좋을 내용)

4. 화면 전환 객체 RootViewSwitcher

final class RootViewSwitcher {
    static let shared = RootViewSwitcher()
    private init() {}

    func setRoot(_ viewController: UIViewController, animated: Bool = true) {
        guard let window = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first?.windows.first else { return }

        window.rootViewController = viewController

        if animated {
            UIView.transition(with: window,
                              duration: 0.3,
                              options: .transitionCrossDissolve,
                              animations: nil,
                              completion: nil)
        }
        
        window.makeKeyAndVisible()
    }
}

매개변수로 뷰를 받고, 루트 뷰로 전환해줍니다.

5. 탭 바 DefaultTabBarSceneFactory

extension TabBarController: UITabBarControllerDelegate {
    
}

protocol TabBarSceneFactory {
    func makeViewController(for tab: TabBarController.Tab) -> UIViewController
}

final class DefaultTabBarSceneFactory: TabBarSceneFactory {
    func makeViewController(for tab: TabBarController.Tab) -> UIViewController {
        switch tab {
        case .jinjae:   return JinJaeViewController()
        case .junbeom:  return CombineViewController_HJB()
        case .seungjun: return ViewController_LSJ()
        }
    }
}

final class TabBarController: UITabBarController {
    
    //MARK: - Properties
    
    var factory: TabBarSceneFactory = DefaultTabBarSceneFactory()
    
    static weak var shared: TabBarController?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        TabBarController.shared = self // 인스턴스 할당 필수!
        ...
    }
}

탭 바 또한 같은 원리로 Factory 객체가 생성 및 전환을 담당합니다.

이렇게 관심사를 분리하면, 알림 뷰 컨트롤러에서 탭 뷰의 전환이 자연스러워집니다.

문제점

화면 전환 관심사의 분리를 통해 발생하는 문제가 있습니다.

  1. 재진입 시, 화면을 새로 그려야 함 (화면을 저장하지 않음)
  2. 재진입 시, ViewModel 객체를 생성해서 주입해주어야 함

DI Container 를 이용하여 ViewModel 등의 객체를 저장하여 (Singleton Pattern 사용 예상) 재진입 시, 저장된 데이터를 사용할 수 있습니다.

ViewModel 에 화면의 상태를 저장한다면 (스크롤 위치, 선택된 사항 등...) 이전 UI 그대로 그릴 수 있습니다.


📷 Screenshots

기능/화면 루트 뷰 전환 탭간 이동
영상 Simulator Screen Recording - iPhone 17 Pro - 2025-12-29 at 17 12 10 Simulator Screen Recording - iPhone 17 Pro - 2025-12-29 at 17 12 20

💬 To Reviewers

  • 리뷰어에게 전달하고 싶은 메시지를 남겨주세요.

@Rudy-009 Rudy-009 requested review from KuKaH and LJIN24 December 29, 2025 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] Factory Pattern 을 이용한 화면 전환

2 participants