EEYatHo 앱 깎는 이야기

Swift ) RIBs - EEYatHo iOS 본문

iOS, Swift/ArchitecturePattern

Swift ) RIBs - EEYatHo iOS

EEYatHo 2021. 7. 5. 18:15
반응형

RIBs 정의


 

기존 디자인패턴들이, 비지니스 로직만 있는 ( 뷰가 없는 ) 모듈의 구현이 어려웠고,

이 점을 보완하여 Uber에서 VIPER를 개조한 것이 RIBs 이다.

 

화면로직이나, 비지니스로직을 RIB 이라는 모듈로 작성한다.

RIB에게 UI요소(View, Presenter)는 옵셔널이다. ( 비지니스 로직만을 가진 모듈이 가능하다는 뜻 )

RIB들을 부모자식 관계로 이어서 논리적인 트리구조로 앱을 작성한다.

 

-> 앱의 상태가 뷰가 아닌, 현재 activate된 RIB이 무엇인가에 따라 결정됨.

 

 

기존 MV*, VIPER같은 디자인패턴들이 SW설계시 참고할 수 있는 아키텍처라면,

RIBs는 프레임워크다.

Cocoa Pod이나 Carthage를 이용해서 설치하고, import 하는 형태다.

 


RIB 구성요소


Builder

  • 부모RIB의 Router로 부터 RIB생성을 위해 자식의 Builder가 호출된다.
  • 구성요소들의 생성 및 DI 한다.
  • Component를 사용하여 빌드함. ( 외부의존성은 Component로 받는다. )
  • Routing ( Router가 네비게이션 할 때 필요한 것을 정의한 프로토콜 )을 리턴하며, 필요에 따라 interacter을 listener, actionableItem 형태로 함께 반환하기도 한다.
  • 팩토리 패턴으로 RIB의 컴포넌트들을 생성해주는 역할을 한다.
  • 클래스들의 Mockability가 향상시켜준다.
  • Builder는 실제 DI 시스템이 어떻게 구현되어 있는지 알고있는 유일한 클래스이다.

 

 

Component

부모RIB의 Builder가 자식RIB의 Builder에 DI하는데 필요한 것을 정의한 프로토콜이다.

 

 

Router

  • RIB간의 전환 ( attach, detach )을 담당하며, 앱의 논리적 트리구조를 형성한다. 
  • Router가 자식RIB을 detach하면, detach된 자식RIB의 Interactor은 deactivate 된다. 반대도 마찬가지다.
  • Builder에게 RIB 생성을 명령하고, 반환된 Routing을 이용해서 Routing한다.
  • Interacter에게 Routing해달라고 요청받는다.
  • didLoad라는 커스텀 생명주기를 가지고 있다. 비지니스 로직만을 가진 RIB이 load된 후, View를 가진 자식RIB으로 Routing 하는 등. 무언가 해야할 때 필요하기 때문.
  • RIB Tree 상에서 어떻게 RIB이 존재할지, 트랜지션이 어떻게 일어날지 결정한다.
  • 다른 Interactor를 호출하는것을 봉쇄시킨다.

 

Interactor

  • 비지니스 로직과 데이터를 관리 한다.
  • API를 어떻게 호출할지, 데이터를 어떻게 저장할지, 어떤 State로 바꿔줄지 Interactor에서 이루어진다.
  • 다른 RIB들간의 통신은 오직 Interactor에서 한다. ( 부모에게 전달할 때는 Listener, 자식에게 전달할 때는 Rx Observable )
  • Presenter에게 데이터나 로직을 요청받고, 전달한다.
  • Router에게 Routing을 요청한다.
  • didBecomeActive, willResignActive 같은 활성화 관련 생명주기를 소유하고 있다. Router에 의해 활성화 되었을 때 무언가 해야할 때 필요하기 때문.

 

Presenter(Optional)

View와 Interactor의 중재자.

View 로직이 필요할 때만 추가한다.

Interactor에게 전달받은 데이터모델을 ViewModel로 변환하여 View에게 전달하는 Stateless class이다.

Presenter이 없는데 View가 있을 경우, ViewModel 생성은 Interacter나 View에서 담당한다.

View에게 유저 이벤트를 전달받고 Interactor에게 필요한 데이터나 로직을 요청한다.

 

 

View(Optional)

UI요소들. ViewController 포함.

Presenter에게 유저 이벤트를 넘긴다.

Presenter에게 ViewModel을 받아서 update한다.

ViewController의 생명주기는 UI요소만 신경쓴다.

 

 


+ @

몇몇 프로토콜들의 역할이나 포함관계를 정리.

[RIB]은 특정 RIB의 이름을 뜻하고

끝에 붙는 (c)는 클래스를 뜻한다. ( 없으면 프로토콜이다. )

 

[RIB]Builder(c) [RIB]Buildable Buildable 

[RIB]Dependency ⊂ Dependency 

Component<Dependency>(c) ⊂ Dependency

 

[RIB]Routing ⊂ ViewableRouting ⊂ Routing ⊂ RouterScope..?

 

[RIB]Interactor ⊂ Interactor, [RIB]Interactable, [RIB]ActionableItem..?

[RIB]Interactable ⊂ Interactable, 자식[RIB]Listener들 

 

[RIB]ViewController ⊂ [RIB]ViewControllable, [RIB]Presentable(프레젠터 생략시에만) 

[RIB]ViewControllable ⊂ ViewControllable 

[RIB]Presentable Presentable

 

[RIB]Listener : 부모RIB의 Interactor을 이 프로토콜로 소유한다.

[RIB]PresentableListener : 같은 RIB에서, View가 Presenter을 소유할 때 사용하는 프로토콜이다.

[RIB]ActionableItem : 딥링크로 앱을 실행했을 때 Workflows와 함께 무언가 한다. 아직은 잘 모른다.

RouterScope : 라우터의 생명주기 관리

 

 


RIBs 특징


 

RIB에서 뷰컨은 옵셔널이기 때문에, 새로운 생명주기가 등장한다.

( didLoad, didBecomeActive, willResignActive 등 )

-> VC의 생명주기는 오직 UI만 담당하게 된다.


높은 Mockabilty를 위한 프로토콜 지향 프로그래밍을 사용한다.

프레임워크단에서 구성요소들에 필요한 것들을 모두 프로토콜화 해놨다.

( RIB간의 attach, detach나 생명주기 관리 등 이미 다 프로토콜화 해놨음. )

 


프레임워크 답게, 여러 지원들이 존재한다.

1. 소스 생성 Templete

2. Tutorial

https://github.com/uber/RIBs/wiki/iOS-Tutorial-1 

 

3. DeepLink를 지원하는 Workflows, actionable item.

 


자식RIB -> 부모RIB : Delegate패턴 ( 프로토콜 이름 : *Listener )

부모RIB -> 자식RIB : Rx Observable

 


정의된 프로토콜이 매우 많고,

Viewless 한 모듈이 새로 나오기 때문에 러닝커브가 제법 크다.

( 튜토리얼이 정말 많은 도움이 되었다. )

 


화면 기반이 아니기 때문에, 타인이 짠 소스의 의도 파악은 더 어렵다.

( 머릿속에서 그려지는 형태가 없기 때문. )

물론, 논리 트리를 어떻게 구성했는지 참고 자료를 남겨두면 괜찮다.

 


프레임워크에서 정의해둔 프로토콜이 매우매우 많기 때문에,

해당 용어들의 의미와, 실행 흐름의 선행 공부가 필수적이다.

 

dependency, ~listener, ~able, ~actionable, routing, scope..

다른 디자인패턴들을 공부할 땐 코드의 큰 구성요소들(model, viewMdoel, reactor 등)만 알면 되었지만, RIBs는 다르다.

마치 iOS를 처음 공부할 때, viewDidLoad나 UITableViewDelegate를 공부하는 느낌을 받았다.

 

물론 정의해둔게 많고, 프레임워크에서 지원해주는 기능이 많기 때문에,

프로토콜 사용과 실행흐름에 익숙해지면 사용성은 높아보인다.

다만, 프레임워크에 대한 의존도도 또한 높다.

 


아직 Viewless 한 모듈이 어떤 장점을 가져다주는지 체감하지 못했다.

실제 서비스에서 Viewless 한 모듈의 필요성이 얼마나 될련지..

 

 

 


레츠스위프트 2018 김남현님

RxRIBs, Multiplatform architecture with Rx - 김남현

 

레츠스위프트 2019 민소네님

MVC, MVVM, ReactorKit, Viper를 거쳐 RIB 정착기 (안정민)

 

Comments