Conversation
- EditCoordinator, EditSceneFactory, EditSceneInput, EditFlow 추가 - AddressSearchCoordinator, AddressSearchSceneFactory, AddressSearchSceneInput 추가 - CalendarFlow, DetailFlow enum 및 FlowEmitting 프로토콜 추가
- CalendarViewControllerDelegate, ImagePickerDelegate 제거 - WeeklyVC, MonthlyVC에 flowSubject/flowPublisher 추가 및 CalendarFlowEmitting 채택 - CalendarViewController에 generic init 도입, 자식 VC publisher 병합 - CalendarSceneFactory가 CalendarViewController 직접 반환 - CalendarCoordinator가 flowPublisher 구독하여 화면 전환 처리
- ImagePickerDelegate, EditDelegate, AddressSearchDelegate 제거 - DetailViewController에 flowSubject/flowPublisher 추가 및 DetailFlowEmitting 채택 - EditFoodRecordViewController에 flowSubject/flowPublisher 추가 및 EditFlowEmitting 채택 - DetailSceneFactory, EditSceneFactory가 UIViewController 직접 반환 - DetailCoordinator, EditCoordinator가 flowPublisher 구독하여 화면 전환 처리
…직접 주입 - DetailSceneFactory: DIContainer 제거, FetchFoodRecordsUseCase / SaveFoodRecordUseCase / DeleteFoodRecordUseCase / PushNotificationObserver 직접 주입, makeDetailScene(input:)에서 ViewModel 자체 생성 - EditSceneFactory: DIContainer 제거, UpdateFoodRecordUseCase / DeleteFoodRecordUseCase 직접 주입 - AddressSearchSceneFactory: DIContainer 제거, SearchAddressUseCase 직접 주입 - SceneDelegate: registerPresentation()에서 DetailVM / EditVM / AddressSearchVM 등록 블록 삭제, makeAppFlowController()에서 각 Factory에 UseCase 직접 전달
- CalendarSceneFactory: WeeklyVM / MonthlyVM 저장 방식 제거, UseCase 8개(requestPhotoAuthorizationUseCase, loadWeeklyCalendarDataUseCase, saveFoodRecordUseCase, pushNotificationObserver, getNicknameUseCase, coachmarkStorage, fetchMonthlyCalendarDaysUseCase, fetchFoodRecordsUseCase) 직접 주입, makeScene()에서 ViewModel 자체 생성 - SceneDelegate: registerPresentation()에서 WeeklyVM / MonthlyVM 등록 블록 삭제, makeAppFlowController()에서 Calendar UseCase를 직접 resolve하여 Factory에 전달, typealias RecordRepo / AssetFetcher 함수 상단 통합
- FlowEmitting 프로토콜(DetailFlowEmitting, EditFlowEmitting, CalendarFlowEmitting) 제거 → Coordinator가 구체 VC 타입의 flowPublisher에 직접 접근 - SceneProducing 프로토콜 반환 타입을 UIViewController에서 구체 VC 타입으로 변경 → 런타임 다운캐스팅(as? any FlowEmitting) 제거 - Factories 구조체 프로퍼티를 any SceneProducing에서 구체 Factory 타입으로 변경 → 컴파일 타임에 타입 정보 보존
There was a problem hiding this comment.
로그인 상태를 책임지는 객체가 하나 있으면 좋을 거 같아서 추가했습니다!
LoginSession
개요
LoginSession은 로그인/로그아웃/탈퇴 이벤트를 Combine Publisher로 전달하는 이벤트 버스 입니다.
기존 NotificationCenter 기반의 인증 이벤트 전달을 대체한다.
구조
graph LR
classDef usecase fill:#5B8DEE,stroke:#333,color:#fff
classDef session fill:#FF6B6B,stroke:#333,color:#fff,font-weight:bold
classDef consumer fill:#4ECDC4,stroke:#333,color:#fff
A["FinalizeAppleLoginUseCase"]:::usecase -->|"notifyLoginSuccess(result)"| S["LoginSession"]:::session
B["LogoutUseCase"]:::usecase -->|"notifyLogout()"| S
C["WithdrawUserUseCase"]:::usecase -->|"notifyLogout()"| S
S -->|"loginResultPublisher"| D["AppFlowController"]:::consumer
S -->|"logoutPublisher"| D
|
|
||
| import UIKit | ||
|
|
||
| public struct Factories { |
There was a problem hiding this comment.
지금 바뀐게 많은데 여기에 추상화까지 더해버리면 이해하기 힘들거 같아서 최대한 추상화는 걷어냈음!
| // MARK: - Screen Routing | ||
|
|
||
| private extension DetailCoordinator { | ||
| func flowBind(vc: DetailViewController<FoodRecordRepositoryImpl<HTTPClient, AuthTokenStorage<KeychainService>>, PushNotificationObserver>) { |
There was a problem hiding this comment.
이것도 추상화를 걷어내서 구체 타입을 알게 되는데, 이 부분은 추후에 테스트 로직 쓸 때 보완할게!!
| import Combine | ||
| import UIKit | ||
| import Data |
There was a problem hiding this comment.
Data 모듈 알게 되는건 이번에 얘기한 제네릭 Erase 적용하면 해결될 듯!
| import Domain | ||
| import Foundation | ||
|
|
||
| public struct DetailSceneInput { |
There was a problem hiding this comment.
DetailVC를 만드는데 필요한 파라미터를 정의한 모델
enebin
left a comment
There was a problem hiding this comment.
아니 해놓고 submit을 안했네.. 일단 이거 하나 있었음
| let loginCoordinator = LoginCoordinator(factories: factories) | ||
| loginCoordinator.sceneTransitioner = sceneTransitioner | ||
| loginCoordinator.parentCoordinator = self | ||
| addChild(loginCoordinator) |
There was a problem hiding this comment.
pushLoginVC() / pushMainVC() 호출 할 때 기존 childCoordinators를 정리하는 코드가 없어서 로그아웃 → 재로그인하면 MainCoordinator가 중복으로 쌓일 것 같음! remove 해주는 코드가 있으면 좋아 보입니당ㅎㅎ
✏️ 변경 내용
Coordinator 패턴 도입
Coordinator프로토콜 및 화면별 Coordinator 추가ViewTransitionHandling프로토콜로 화면 전환 애니메이션 추상화 (기존 AppFlowController의 transition(_:))ViewModelFactory 추가 — DI Container에서 ViewModel 등록 제거
SceneDelegate에서 DI Container에 ViewModel을 직접 등록 → 팩토리 클로저가 연쇄적으로 중첩되는 구조SceneFactory가 UseCase만 주입받아 ViewModel/VC를 직접 생성연쇄 Factory 클로저 제거
AppFlowController내부에서 VC 생성 시 중첩 클로저로 하위 화면까지 연쇄 생성하는 구조AppFlowController 책임 분배
AppFlowController가 담당하던 역할을 분리기타 개선
LoginSession도입으로 로그인/로그아웃/탈퇴 이벤트를 Combine Publisher로 통합CoachmarkStorage추가Coordinator 구조
graph TD classDef root fill:#FF6B6B,stroke:#333,color:#fff,font-weight:bold classDef auth fill:#FFA07A,stroke:#333,color:#fff classDef tab fill:#4ECDC4,stroke:#333,color:#fff,font-weight:bold classDef tabChild fill:#45B7AA,stroke:#333,color:#fff classDef detail fill:#5B8DEE,stroke:#333,color:#fff classDef leaf fill:#A78BFA,stroke:#333,color:#fff classDef modal fill:#F59E0B,stroke:#333,color:#fff App["🏠 AppCoordinator"]:::root App -->|"replace scene"| Login["🔐 LoginCoordinator"]:::auth App -->|"replace scene"| Main["📱 MainCoordinator"]:::tab App -.->|"deep link"| Detail Main -->|"Tab 1"| Calendar["📅 CalendarCoordinator"]:::tabChild Main -->|"Tab 2"| Insight["📊 InsightCoordinator"]:::tabChild Main -->|"push"| MyPage["👤 MyPageCoordinator"]:::tabChild Calendar -->|"push"| Detail["🍽️ DetailCoordinator"]:::detail Calendar -->|"push"| IP1["🖼️ ImagePickerCoordinator"]:::leaf Detail -->|"push"| Edit["✏️ EditCoordinator"]:::detail Detail -->|"push"| IP2["🖼️ ImagePickerCoordinator"]:::leaf Edit -->|"modal"| Address["📍 AddressSearchCoordinator"]:::modal