[iOS] RIBs

hyun·2023년 12월 16일
0

RIBs 특징

  • 전역 상태 문제 방지: 잘 격리된 개별 RIB 구조 내에서 상태 캡슐화
  • 독립적인 테스트 가능 : 개별 RIB 클래스에는 고유한 책임이 있음(예: 라우팅, 비즈니스 로직, 뷰 로직, 다른 RIB 클래스 생성), 상위 RIB 로직은 하위 RIB 로직과 분리됨
  • Open-Closed Principle: 상위 RIB를 거의 변경하지 않고도 상위 RIB의 종속성이 필요한 복잡한 하위 RIB를 연결하거나 빌드 가능

구조

  • Interactor
    • Interactor에는 비즈니스 로직이 포함됨.
    • Rx 구독 수행, 상태 변경 결정, 데이터를 저장할 위치 결정, attach될 child RIB 결정
    • 비즈니스 로직은 lifecycle 내(=Interactor가 active 상태)에서 실행되야 함 -> Interactor가 비활성화되었는데도 구독이 지속되어 비즈니스 로직이나 UI 업데이트가 되는 시나리오 방지

(위 설명만 읽었을 때는 Interactor는 익숙한 MVVM패턴으로 따지면 ViewModel과 같은 역할을 하는것 같다..)

  • Router
    • Router는 Interactor의 말을 듣고(listen), 그 output으로 child RIB 연결(attach) 및 분리(detach)로 변환
    • Router의 존재 이유
      • mock child Interactor의 도움 없이 복잡한 Interactor 로직 테스트 가능하게 해준다.
      • Router는 parent Interator와 child Interactor 사이에 추상 계층(abstraction layer)을 생성한다 -> Interactor 사이에 동기적 통신이 어려워지고, RIBs간의 직접 결합(coupling) 보다는 reactive 통신을 채택하도록 한다.
      • Router에는 Interactor에 의해 구현되는 반복적인 로직이 포함되어 있다.
  • Builder
    • RIB의 모든 구성 클래스와 각 RIB의 자식에 대한 Builder를 인스턴스화한다.
    • Builder를 구성한다는 것(= 클래스 생성 로직을 분리한다는 것)은 mockability를 지원한다는 것이고, 나머지 RIB의 코드에는 DI 구현과 무관해진다는 뜻이다. Builder가 DI 시스템을 알고있어야 하는 유일한 객체이다.
  • Presenter
    • business model을 view model로 변환하거나 그 반대로 변환한다.
    • 종종 Presenter 클래스가 생략되기도 한다.
    • 만약 Presenter 클래스가 생략되면, view model로의 변환은 View나 Interactor에서 담당한다.
  • View(Controller)
    • UI 생성, 레이아웃, 사용자 인터렉션 처리, 데이터에 따른 UI 변화, 애니메이션 담당.
    • 정보를 화면에 표시하는 역할만 한다.
    • 단위테스트가 필요한 코드는 없음.
  • Component
    • Component는 RIB 종속성(dependencies)을 관리하는데 사용
    • Builder를 도와, RIB을 구성하는 다른 units을 인스턴스화하는데 도움을 준다.
    • RIB 자체에서 생성된 종속성을 소유하고, 다른 RIB의 액세스를 제어할 수 있다.
    • 상위 RIB의 Component는 하위 RIB의 Builder에 주입되어, 하위 RIB의 종속성에 대한 액세스를 제공한다.

State Management

RIBs는 그들의 범위에 있는 state 결정을 내린다.





Communication between RIBs

  • Interactor가 비즈니스 로직을 결정할때, 다른 RIB의 이벤트에 완료 이벤트를 알리거나 데이터를 전송해야할 때도 있다.

  • child RIB으로 통신이 이뤄지면, 데이터를 Rx 스트림으로 방출하거나 child RIB의 build() 메소드의 파라미터로 포함될 수 있다.

    위 이미지는 Rx를 통한 하향 통신 방식의 예이다.

  • parent RIB의 Interactor로 올라가는 통신의 경우, 통신은 listener interface를 통해 이뤄진다. parent RIB이나 DI 그래프의 일부 객체는 listener interface를 구현하고, child RIB이 호출할 수 있도록 한다.

  • 부모가 자식의 Rx를 구독하는 것보다 위 방법을 사용하는 것이 메모리 누수를 방지하고, 부모가 어떤 자식이 연결되어 있는지 모른채 프로젝트를 구성할 수 있다는 장점이 있다.

위 이미지는 listener interface를 통한 상향 통신 방식의 예이다.


참고
https://github.com/uber/RIBs/wiki

0개의 댓글