빙수왕의 개발일지

RIBs iOS Tutorial 1 본문

개발/iOS

RIBs iOS Tutorial 1

빙수킹 2021. 12. 19. 03:20

튜토리얼 따라하기.

https://github.com/uber/RIBs/tree/master/ios/tutorials/tutorial1

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

 

Tutorial1


사전작업 - RIBs 파일 생성을 위한 template 설치, pod install


RIBs/ios/tooling 이동하여 template 설치

install-xcode-template.sh

RIBs/ios/tutorials/tutorial1 이동하여 pod 설치

pod install

pod install 하자마자 문제 발생.

CocoaPods could not find compatible versions for pod "RxRelay"

Podfile 열어봄

target 'TicTacToe' do
  pod 'RIBs', :path => '../../../'
  pod 'SnapKit', '~> 4.0.0'
  pod 'RxCocoa', '~> 5.1'

vi RIBs.podspec 확인

Pod::Spec.new do |s|
  s.name             = 'RIBs'
  s.version          = '0.9.3'
  s.summary          = 'Uber\'s cross-platform mobile architecture.'
  s.description      = <<-DESC
RIBs is the cross-platform architecture behind many mobile apps at Uber. This architecture framework is designed for mobile apps with a large number of engineers and nested states.
                       DESC
  s.homepage         = 'https://github.com/uber/RIBs'
  s.license          = { :type => 'Apache License, Version 2.0', :file => 'LICENSE.txt' }
  s.author           = { 'uber' => 'mobile-open-source@uber.com' }
  s.source           = { :git => 'https://github.com/uber/RIBs.git', :tag => 'v' + s.version.to_s }
  s.ios.deployment_target = '9.0'
  s.source_files = 'ios/RIBs/Classes/**/*'
  s.dependency 'RxSwift', '~> 6.0.0'
  s.dependency 'RxRelay', '~> 6.0.0'

RxCocoa 버전 변경함 (5.1 → 6.0)

target 'TicTacToe' do
  pod 'RIBs', :path => '../../../'
  pod 'SnapKit', '~> 4.0.0'
  pod 'RxCocoa', '~> 6.0'
end

빌드 성공!

 

wiki 설명


목표

RIB에서 서로 어떻게 상호작용하고 소통하는지 알아보자. 이름을 입력하고 로그인 버튼을 누르면 콘솔에 이름을 출력하는 프로그램을 만들어보자.

프로젝트 구조

두 개의 RIB로 구성된 iOS 프로젝트가 있다. 앱이 실행되면, AppDelegate는 루트 RIB를 구축하고 애플리케이션에 대한 제어를 전송. Root RIB의 목적은 RIB 트리의 루트 역할을 하고 필요할 때 자식에게 제어를 전달하는 것이다. 루트 RIB의 코드는 대부분 Xcode 템플릿에 의해 자동 생성되며, 이 코드를 이해하는 것은 여기서 필요하지 않다.

TicTacToe 앱의 두 번째 RIB는 LoggedOut이라고 불리며, 로그인 인터페이스를 포함하고 인증 관련 이벤트를 관리해야 합니다. 루트 RIB가 AppDelegate에서 앱을 제어하면, 즉시 LoggedOut RIB로 전송하여 로그인 양식을 표시합니다. LoggedOut RIB를 구축하고 제시하는 코드는 이미 제공되며 RootRouter에서 찾을 수 있습니다.

현재로서는 LoggedOut RIB가 구현되지 않았다. LoggedOut 그룹을 열면, 코드를 컴파일하는 데 필요한 일부 스텁이 있는 DELETE_ME.swift 파일만 찾을 수 있습니다. 이 튜토리얼에서, 우리는 LoggedOut RIB의 적절한 구현을 만들 것이다.

 

LoggedOut RIB 만들기

new file - RIB 선택

"Owns corresponding view" 체크하면 View Controller를 가진 RIB로 생긴다.

 

LoggedOut UI

VC에 뷰를 그려줘야함. 귀찮다면 이미 이사람들이 그려준게 있으므로.. 다음 코드를 LoggedOutViewController에 복붙한다.

https://raw.githubusercontent.com/uber/ribs/assets/tutorial_assets/ios/tutorial1-create-a-rib/source/source1.swift

다만 스냅킷이 있어야한다. 맨위에 스냅킷 임포트 해줌.

import SnapKit 

 

VC에서 Interactor로 값 보내기

vc에서 버튼을 클릭하면 비즈니스로직 수행을 위해 interactor로 값을 보내야한다. 이미 vc에 LoggedOutPresentableListener이라는 protocol이 프로퍼티로 들어가있다. 이 listener에 login 메소드를 만들어주고 구현하자.

protocol LoggedOutPresentableListener: AnyObject {
    // TODO: Declare properties and methods that the view controller can invoke to perform
    // business logic, such as signIn(). This protocol is implemented by the corresponding
    // interactor class.
    func login(with player1Name: String?, with player2Name: String?)
}

튜토리얼에서는 playerName의 optional binding하는 메소드를 만들었지만, 난 귀찮아서 그냥 함..

func login(with player1Name: String?, with player2Name: String?) {
        let player1Name = player1Name ?? ""
        let player2Name = player2Name ?? ""

        print("\(player1Name) vs \(player2Name)" )
    }

그리고 마지막으로 사용자가 버튼을 눌렀을 떄 login 메소드를 호출해주자.

@objc private func didTapLoginButton() {
        listener?.login(with: player1Field?.text, with: player2Field?.text)
    }

 

결과

버튼 눌렀을 때.. 출력 잘 되는걸 볼 수 있다.

 

정리

  1. template를 사용해서 RIB를 만들어봤다.
  2. RIB 생성 시 "Owns corresponding view" 체크하면 View Controller를 가진 RIB로 생긴다.
  3. VC → Interactor로 communicate 하는 방법은 listener을 통해서 한다.
    • SOLID중 D 의존성 역전 원칙.
    • 그러니까 사실 vc가 interactor을 알고 있으면 안되는데, interactor가 listener이라는 protocol에 의존하고, vc는 이 protocol을 알고 있는 것이므로(이놈이 interactor이라는 사실은 모른다) vc가 interactor과 상관이 없는 독립적인 컴포넌트로 만들어주고, vc를 testable하게 해준다.
    • 이 때 listener는 weak var로 만들어줘서 순환참조에 의한 메모리릭을 방지한다.
    • 왜 weak인가? unowned로 하면 listener가 없을 때 앱이 죽을 수 있다. interactor가 메모리에서 사라졌을 때 vc에서 쓸모없는 작동이 일어나지 않도록 미연에 방지한다. interactor의 생명주기 ≤ vc의 생명주기

 

그 외 궁금한 것

  1. vc → Interactor은 listener로 통신한다. interactor → router역시 이와 동일(프로퍼티 이름은 router)하다. 그렇다면 반대 방향은?
    • interactor → vc의 경우, interactor은 presneter형태로 vc를 프로퍼티로 가지고 있다. 그래서 그냥 presneter.method() 이렇게 해주는듯. 이 때 interactor은 presenter을 완전히 알고 있다고 할 수 있다. 그래서 강하게 참조한다. router → interactor 역시 이와 동일하게 router에서 interactor을 프로퍼티로 강하게 참조하고 있다.

'개발 > iOS' 카테고리의 다른 글

RIBs iOS Tutorial 3  (0) 2021.12.21
RIBs iOS Tutorial 2  (0) 2021.12.19
App Signing에 대하여  (1) 2021.12.15
iOS) UIButton Custom해서 CheckBox 만들기  (1) 2021.09.23
ARC in Swift: Basics and beyond  (0) 2021.09.01