RIBs Study Guide

RIBs 아키텍처 빠른 이해

이 문서는 작동하는 최소 샘플을 기준으로 RIBs의 핵심만 빠르게 익히도록 구성했습니다.

1. 초등학생 버전으로 먼저 이해하기

RIBs는 "역할 나눠서 일하는 팀"입니다.

즉, 한 사람이 다 하는 게 아니라 각자 맡은 일만 하니까 실수가 줄고 고치기 쉬워집니다.

2. 처음 보는 사람용 1분 요약

이 패턴의 핵심은 UI/로직/이동 책임 분리입니다.

3. RIBs를 왜 쓰나?

4. 6요소 한 줄 요약 (풀 구조)

5. 이번 샘플 구조

ribsSample/
  RIBsCore/
    RIBsCore.swift
  Root/
    RootBuilder.swift
    RootComponent.swift
    RootPresenter.swift
    RootRouter.swift
    RootInteractor.swift
    RootViewController.swift
  LoggedOut/
    LoggedOutBuilder.swift
    LoggedOutComponent.swift
    LoggedOutPresenter.swift
    LoggedOutRouter.swift
    LoggedOutInteractor.swift
    LoggedOutViewController.swift
  LoggedIn/
    LoggedInBuilder.swift
    LoggedInComponent.swift
    LoggedInPresenter.swift
    LoggedInRouter.swift
    LoggedInInteractor.swift
    LoggedInViewController.swift
실행 흐름
SceneDelegateRootBuilder.build()RootRouter.launch()LoggedOutBuilder.build()
로그인 버튼 탭 시: LoggedOutViewControllerLoggedOutPresenterLoggedOutInteractorRootInteractorRootRouter (LoggedIn attach)
로그아웃 버튼 탭 시: LoggedInViewControllerLoggedInPresenterLoggedInInteractorRootInteractorRootRouter (LoggedOut attach)

6. 핵심 코드 포인트

파일 읽기 순서

1-1 SceneDelegate → 1-2 RootBuilder → 1-3 RootComponent → 1-4 RootRouter → 1-5 RootInteractor → 1-6 RootPresenter → 1-7 RootViewController

2-1 LoggedOutBuilder → 2-2 LoggedOutComponent → 2-3 LoggedOutViewController → 2-4 LoggedOutPresenter → 2-5 LoggedOutInteractor → 2-6 LoggedOutRouter

3-1 LoggedInComponent → 3-2 LoggedInViewController → 3-3 LoggedInPresenter → 3-4 LoggedInInteractor → 3-5 LoggedInRouter → 3-6 LoggedInBuilder

A) 조립 시작점

RootBuilder.swift에서 Root RIB을 만들고, Scene에서 launch 합니다.

B) 이벤트 전달

LoggedOutViewController.swift는 버튼 입력을 Presenter로 전달합니다.

C) 상태 처리

LoggedOutInteractor.swift는 상태를 계산하고 Presenter/Root에 이벤트를 전달합니다.

D) 상위 라우팅 반영

RootRouter.swift는 로그인 시 LoggedOut를 detach하고 LoggedIn을 attach하며, 로그아웃 시 반대로 복귀시킵니다.

7. 앱 실행부터 Login Action까지 시퀀스 다이어그램

아래는 실제 샘플 코드 기준 Mermaid 시퀀스 다이어그램입니다.

등장 객체
iOS Runtime, SceneDelegate, RootBuilder, RootComponent, RootRouter, RootInteractor, RootPresenter, RootViewController, LoggedOutBuilder, LoggedOutComponent, LoggedOutPresenter, LoggedOutInteractor, LoggedOutViewController, LoggedInBuilder, LoggedInComponent, LoggedInPresenter, LoggedInInteractor, LoggedInViewController
sequenceDiagram
autonumber
actor User as 사용자
participant iOS as iOS Runtime
participant SD as SceneDelegate
participant RB as RootBuilder
participant RC as RootComponent
participant RR as RootRouter
participant RI as RootInteractor
participant RP as RootPresenter
participant RVC as RootViewController
participant LOB as LoggedOutBuilder
participant LOC as LoggedOutComponent
participant LOP as LoggedOutPresenter
participant LOI as LoggedOutInteractor
participant LOVC as LoggedOutViewController
participant LIB as LoggedInBuilder
participant LIC as LoggedInComponent
participant LIP as LoggedInPresenter
participant LII as LoggedInInteractor
participant LIVC as LoggedInViewController

iOS->>SD: scene(_:willConnectTo:options:)
SD->>RB: build()
RB->>RC: RootComponent 생성
RB->>RVC: RootViewController 생성
RB->>RP: RootPresenter(view) 생성
RB->>RI: RootInteractor(presenter) 생성
RB->>LOB: LoggedOutBuilder(dependency: RC) 생성
RB->>RR: RootRouter 생성
RB-->>SD: (router, viewController) 반환

SD->>SD: UIWindow 설정 / makeKeyAndVisible()
SD->>RR: launch()

RR->>RI: interactor.listener = self
RR->>RI: activate()
RI->>RP: presentLoggedOutState()
RP->>RVC: showStatus("State: LoggedOut")

RR->>LOB: build(listener: RI)
LOB->>LOC: LoggedOutComponent 생성
LOB->>LOVC: LoggedOutViewController 생성
LOB->>LOP: LoggedOutPresenter(view) 생성
LOB->>LOI: LoggedOutInteractor(presenter, initialUserName) 생성
LOB->>LOP: presenter.listener = interactor
LOB->>LOI: interactor.listener = RootInteractor
LOB->>LOI: activate()
LOI->>LOP: presentInitialState(initialUserName)
LOP->>LOVC: show(title) + setUserName(...)
LOB-->>RR: LoggedOutRouter 반환

RR->>RR: attachChild(loggedOutRouter)
RR->>RVC: set(content: LOVC)
Note over RVC: addChild -> addSubview -> constraints -> didMove

User->>LOVC: Login Action 버튼 탭
LOVC->>LOP: didTapLoginButton(userName)
LOP->>LOI: loggedOutPresenterDidTapLoginButton(userName)
LOI->>LOP: presentWelcome(userName)
LOP->>LOVC: show(title: "Welcome, ...")
LOI->>RI: loggedOutDidRequestLogin(userName)
RI->>RP: presentLoggedInState(userName)
RP->>RVC: showStatus("State: LoggedIn as ...")
RI->>RR: rootDidLogin(userName)

RR->>RR: detachChild(loggedOutRouter)
RR->>LIB: build(listener: RI, userName)
LIB->>LIC: LoggedInComponent 생성
LIB->>LIVC: LoggedInViewController 생성
LIB->>LIP: LoggedInPresenter(view) 생성
LIB->>LII: LoggedInInteractor(presenter, userName) 생성
LIB->>LIP: presenter.listener = interactor
LIB->>LII: interactor.listener = RootInteractor
LIB->>LII: activate()
LII->>LIP: presentLoggedIn(userName, appName)
LIP->>LIVC: show(title/detail)
RR->>RR: attachChild(loggedInRouter)
RR->>RVC: set(content: LIVC)

User->>LIVC: Logout 버튼 탭
LIVC->>LIP: didTapLogoutButton()
LIP->>LII: loggedInPresenterDidTapLogout()
LII->>RI: loggedInDidRequestLogout()
RI->>RP: presentLoggedOutState()
RP->>RVC: showStatus("State: LoggedOut")
RI->>RR: rootDidLogout()
RR->>RR: detachChild(loggedInRouter)
RR->>LOB: build(listener: RI)
RR->>RVC: set(content: LOVC)

시각 타임라인

1) iOS Runtime → SceneDelegate.scene(...)
2) SceneDelegateRootBuilder.build() 호출
3) Root 조립 완료: RootComponent + RootPresenter + RootRouter + RootInteractor + RootViewController
4) 윈도우 루트 설정 후 RootRouter.launch()
5) RootRouterLoggedOutBuilder.build(listener: RootInteractor) 실행
6) LoggedOutInteractor.activate()LoggedOutPresenter → 화면 초기 표시
7) 사용자 버튼 탭: LoggedOutViewController.didTapButton()
8) 이벤트 전파: LoggedOutViewControllerLoggedOutPresenterLoggedOutInteractorRootInteractor
9) RootRouterLoggedIn을 attach하고 화면 전환
10) LoggedIn 화면에서 Logout 탭 시 LoggedOut으로 복귀

초보자용 단계 설명

8. 빌드 방법

xcodebuild \
  -project examples/ribs-sample/ribsSample.xcodeproj \
  -scheme ribsSample \
  -destination 'generic/platform=iOS Simulator' \
  -derivedDataPath /private/tmp/ribsSampleDerived \
  build

로컬 환경에 따라 Simulator 서비스 오류가 나면 Xcode에서 직접 실행해도 됩니다.

9. 다음 학습 순서

10. 이번 대화 핵심 정리

A) 하위 전환 vs 상위 이벤트

B) Root와 Non-root Listener 차이

C) Presenter와 ViewController 의존 방향

D) Root 비대화 방지 원칙