iOS | RIBs – 3. 튜토리얼❷ (RIB Tree간의 이동, Dependency, Component)

안녕하세용


이번 글은 iOS | RIBs – 2. 튜토리얼❶ (RIBs 설치, LaunchRouter 설정, RIB Templete 설정) 에서
계속 됩니다.


본문의 내용이 이해가 안간다 !!!!!!!!! 난 코드만 우선 볼래 !!!!!!!!!! 싶으신 분들은
제가 써가는 코드들의 commit이나 리포지토리를 참고 부탁드려용

🦾 공식 자료

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

💪 이 글에서 진행된 코드의 Repository

https://github.com/unnnyong/RIBsTraining



🌟 본문은 https://github.com/uber/RIBs/wiki 의 튜토리얼을 그대로 따라합니다.

튜토리얼의 RIB Tree


튜토리얼에서 만든건 LoggedOut 에서의 Login 버튼의 구현까지였지요.
이번에 만들 것은 로그인이 성공된 다음의 화면입니다.

RIB Tree를 살펴보면 LoggedIn 으로 넘어오고
그 다음은 TicTacToe, OffGame 두 가지의 RIB 로 나눠지게 됩니다.

자, LoggedOut RIB에서 LogginOut RIB 로 전환하는 것부터 하러 가시죠 ~ ! 🚗🚕🚙


펭수밴드 Instagram posts (photos and videos) - Picuki.com




1. 부모 RIB 와 통신하기

LoggedOutVC 에서 플레이어 1, 2 이름을 입력하고 로그인을 하면,
LoggedInRIB를 통해, TicTacToe의 게임 ViewController가 유저에게 보여져야 하쥬

1) LoggedOut RIB 가 Root RIB 에게 로그인 완료된 상태를 알리기.

– VC 에서 유저가 Login 버튼을 터치하고, Interactor가 버튼을 터치한 것에 대한 작업을 수행해요.
– Login이 성공하면 LoggedOutInteractorRoot RIB 에게 “로그인이 성공했어요! 저 대신 LoggedIn RIB 를 불러주세요” 라고 알려야해요.
LoggedOut RIB가 RootRouter와 연결되어 있는 LoggedOutListener protocol 를 이용하면 알릴 수 있어요.

protocol LoggedOutListener: class {
    // ⭐️
    func didLogin(player1Name: String, player2Name: String)
}

extension LoggedOutInteractor: LoggedOutPresentableListener {
    func login(player1Name: String?, player2Name: String?) {
        let player1Name = player1Name ?? "Default"
        let player2Name = player2Name ?? "Default"

        // ⭐️
        listener?.didLogin(player1Name: player1Name, player2Name: player2Name)
    }
}

🔗 코드 commit 링크


https://github.com/unnnyong/RIBsTraining/blob/3c1a81c3df575d09d948e1e7bb5c1b2093b133f9/RIBsPractice/RIBsPractice/Root/RootRouter.swift#L11

RootInteractable protocol 은 LoggedOutListener protocol을 준수하고 있기 때문에

https://github.com/unnnyong/RIBsTraining/blob/3c1a81c3df575d09d948e1e7bb5c1b2093b133f9/RIBsPractice/RIBsPractice/Root/RootInteractor.swift#L20

RootInteractable protocol 을 준수하는 RootInteractor 에서! 위에서 추가한 didLogin 메소드를 구현해 주세용






2. 다른 RIB로 라우팅 (전환)

Root RIB 도 로그인이 완료되었다는 사실을 알았으니 LoggedOut RIB는 유저에게 보여질 필요가 없어졌어요.
LoggedIn RIB로 갈아탑시다 🤽‍♀️

1) 프로젝트에 LoggedIn RIB를 새로 만들기.

🔗 add LoggedIn RIB files commit
– LoggedIn 에서 실제로 표시되는 화면은 없기 때문에 VC 는 존재하지 않아요. 지금 단계에서는 빌드를 위해 삭제하지 않으셔도 괜찮아요 ! 조금 뒤에서 VC 파일을 삭제하고 수정한답니다.

– Root RIB에서 LoggedIn RIB 를 사용하기 위해서는 RootRouter에 추가해줘야 되겠지유 ?
🔗 add LoggedIn RIB in RootRouter commit


2) LoggedOut RIB 에서 LoggedInRIB 로 전환.

🔗
🔗

LoggedIn RIB로 이동시킬 routeToLoggedIn 메소드를 RootRouting 프로토콜에 추가해 줍니다.

🔗

– 위에서 새로 추가한 routeToLoggedIn 을 사용할 didLogin 메소드를 추가합니다.
– 미리 스포일러를 조금 하자면 LoggedOut에서 불려져야 해요 !!!!!!!!! (미리 구현할 수 있으신 분들은 적절하게 넣어보세용)


3) Root RIB 에서 LoggedOut RIB/LoggedIn RIB 을 바로 전환할 수 있게 수정하기.

🔗 add detaching LoggedOut codes, attach LoggedIn codes commit
– 위에서 추가한 routeToLoggedIn 은 유저가 LoggedOut 에서 로그인을 하게 되면 RootInteractor 에서 불려지게 됩니다.
routeToLoggedIn 의 할일은 함수명 그대로 ! LoggedOut RIB를 종료하고 Root RIB 로 돌아가 LoggedIn RIB로 접속시켜야 합니다.


4) 실제로 유저에게 보여지는 View는 없는 LoggedIn RIB 를 위한 설정.
– 제가 코드를 써보니 이 타이밍보다는 OffGame RIB를 접속시킨 다음에 하는 편이 좋았어서 조금 더 뒤에서 적을게요.


3. LoggedIn RIB 의 자식 RIB 들을 연결하기

1) OffGame RIB 를 프로젝트 파일에 추가

– 저는 Storyboard를 사용합니다. 코드로 UI 쓰실 분들은 VC에서 작성하셔도 괜찮아요 !
🔗add OffGame RIB files commit


– Storyboard에서 UIButton 을 추가하고, VC에 UIButton의 IBAction을 추가해주었어요.
🔗 add StartGame Button at OffGameVC commit



1-1) Storyboard로 VC 를 초기화하도록 수정. Storyboard를 사용하시는 분들만 해당
🔗 commit





2) LoggedIn RIB 에 OffGame RIB 를 연결하기.

지금까지 만든 화면과 RIB tree를 함께 살펴보면,
Root ~ OffGame 에서 유저에게 실제로 보여지는 화면은 OffGameVC만 존재합니다.
= Root Router에서 LoggedIn RIB 로 present 를 실행시키면,
바로 OffGame RIB가 연결되고 OffGameVC가 유저에게 보여져야합니다.




가장 큰(?) 부모인 Root -> LoggedIn 부터 구현해봅시다 💪

부모(Root) RIB와 자식(LoggedIn) RIB의 가장 큰 차이점은
부모(Root)는 실제 표시되지는 않지만 RootViewController가 존재하고
자식(LoggedIn) 에서는 ViewController 자체가 존재하지 않아요.

이럴 때에 자식(LoggedIn)가 부모(Root)의 RIB를 빌려서 사용해요.

⭐️⭐️⭐️⭐️⭐️
자식 RIB 에게 필요한 요소를 부모 RIB 가 준비해야할 때에는
Component와 Dependency 를 활용해야 해요.

(RIB를 생성시키면 Builder 파일의 가장 위에
Component class와 Dependency protocol 이 생성되어있어요.)

⭐️ RIB의 Dependencies 와 Components ⭐️
(공식 튜토리얼 에서는 4번째에 있던 설명이지만 일찍 짚고 넘어갈게요)

Dependency
– RIB가 부모 RIB 에서 만들어질 때, 필요한 Dependency(종속성)로 구성된 프로토콜.

Component
Dependency protocol 를 구현하는 class.
– RIB Builder 에 부모 RIB의 dependency 를 제공하고, RIB가 본인과 본인의 자식 RIB들을 만드는 Dependency를 가져야 한다.

사용
부모 RIB는 자식 RIB를 만들 때,
자신의 Component를 자식의 Builder의 Constructor dependency 로 주입한다.
주입된 Component는 자체적으로 어떤 Dependency를 자식 RIB에게 종속시킬 것인가 결정한다.

Component에 포함된 Dependency 는
DI tree 로 전달되어야 하는 것들을 가지고 performance 이유로
구성하고 공유하는데 수고가 많이 들어간다 ( =메모리도 코드적는 나도 복잡하고 귀찮다)


LoggedIn RIB가 부모 RIB의 ViewController가 필요하므로
LoggedIn Dependency에 viewController를 추가해줍니다.

– 우선 LoggedInDependency loggedInViewController 추가.

LoggedInDependencyloggedInViewController RootComponent로부터 받아와야 함.
RootComponentLoggedInDependency를 계승받도록 하고 loggedInViewController 를 구현.

RootComponent의 초기화 타이밍에 새로 추가한 rootViewController에 실제로 존재하는 RootViewController를 대입합니다.

LoggedInRouterviewControllerRootComponent를 통해 주어지는 값을 대입합니다.

🔗 commit
– 여기까지의 과정으로 Root RIB -> LoggedIn RIB에서 부모의 VC가 전해지도록 수정하였어요 !



LoggedInViewController는 필요없어졌으니 삭제하고,
완전히 RootViewController가 표시되도록 할거예요.

– LoggedInVC를 삭제합니다 안녕 – ! 👋🏻
– 그럼 프로토콜과 관련되어있던 class에 컴파일 에러가 발생하기 시작할거예요 ⛔️⛔️⛔️⛔️
– 당황하지 말고 하나씩 해결해보아요

– 삭제했던 파일을 다시 살펴보면 크게 두 가지 수정이 필요해요 !
– 삭제한 VC 파일에서 만들었던 LoggedInPresentableListener 가 필요했던 LoggedInInteractor의 수정.
– VC class에서 사용한 LoggedInPresentable, LoggedInControllable도 수정.

그리고 기존의 RIB는 View를 사용한다는 전제로 구현되어있었기 때문에
Presetable 또는 Viewable이 붙어있는 property들이 구현되어있어요.
이 property들도 View가 없는 상태로 구현될 수 있도록 수정이 필요합니다.
예) PresentableInteractor -> Interactor, ViewableRouter -> Router, ViewableRouting -> Routing

🔗 commit





LoggedIn RIB에 OffGame RIB 를 아직 추가하지 않았으니 추가해보아요

– OffGameDependency를 우선 LoggedInComponent를 추가시키고

🔗

– Router에 offGameBuilder, offGame의 두 가지 property를 추가합니다.

🔗

LoggedInRouterinit의 parameter가 추가되었으니 사용하는 Builder의 코드도 쓰윽 수정해줍시다 !



RootRIB에서 LoggedIn 으로 presenter를 한 것과 똑같은 흐름으로
RootRIB에서 LoggedIn에 넘어오자마자, OffGame RIB를 열도록 코드를 추가해줍니다.


🔗

– Router의 didLoad()는 ViewController의 viewDidLoad()와 비슷해요. Router가 준비되면 바로 실행되는 메소드예요.


🔗 지금까지의 commit
– present 메소드 구현이 헷갈리시는 분들은 👆을 참고해주시와요




3) (선택사항) Root, LoggedIn 에서 사용되는 present, dismiss 메소드을 통일시키기.
Root가 LoggedOut, LoggedIn에서 왔다갔다 할 때의 present, dismiss가 중복된다고 생각되어서 통일시켰어요.
🔗 commit





4. Start Game 버튼을 터치하고,
TicTacToe RIB 를 열기.

OffGame의 Start Game 버튼을 터치하면 TicTacToe RIB로 흘러가는 것을 구현합니다.

OffGameVC의 Start Game 버튼을 유저가 터치하면,
OffGame에서 TicTacToe를 바로 여는게 아니라
LoggedIn을 거쳐서 LoggedIn에서 TicTacToe를 열어야 합니다.

OffGame과 TicTacToe는 서로의 존재와 상태를 전혀 모르고
양쪽의 부모인 LoggedIn가 적절한 화면이 나오도록 컨트롤합니다.

Tree 구조를 계속 구현하고 되돌리는게 RIBs의 핵심인거 같아요 ! (이제와서,,,,😒)


1) TicTacToe RIB 추가하기.
또다시 이제와서의 이야기지만 저는 TicTacToe가 어떤게임인지 튜토리얼 덕분에 알았네요 ㅋㅋㅋㅋㅋㅋㅋ
저는 TicTacToe 게임, 알고리즘은 구현하지 않을거예요 ! (당당)


– RIB는 지금까지 추가한 RIB와 똑같이 storyboard포함으로 만들어주었어용




아래 내용은 유저가 OffGame을 눌렀을 때의 내부적인 동작의 순서입니다.

1️⃣
LoggedIn 으로 돌아가는 트리거가 되는 동작은
유저가 OffGame의 Start Game 버튼을 누르는 순간입니다.
2️⃣
VC의 실질적인 동작을 하는 친구인 Interaction이 유저가 버튼을 눌렀다는 소식을 전해 받고,
Interactor가 연결되어있는 부모(LoggedIn Interactor)에 게임을 시작해야 한다고 알립니다.
3️⃣
LoggedIn의 자식들을 관리하는 LoggedInRouter가 소식을 전해듣고
OffGame을 떼어내고 TicTacToe를 연결시킵니다.


2) OffGame 의 StartGame 버튼의 동작 추가. (1️⃣ ~ 2️⃣)

OffGameViewControllerOffGameInteractor에게 버튼이 터치된 다음의 행동을 요청할 수 있는 메소드를 사용하기 위해
두 가지가 연결되어있는 OffGamePresentableListenerstartGame() 메소드를 추가합니다.

🔗
🔗

– 추가한 메소드를 didStartButton IBAction에서 사용해주세용


그리고,
OffGamePresentableListenerstartGame()을 OffGameInteractor에서 구현합니다. 🔗




3) OffGame을 dismiss 하도록 LoggedIn RIB에서 구현(3️⃣)

지금까지 무사히 따라오셨다면,
OffGameInteractorstartGame()의 메소드에는 아무 코드도 들어있지 않을거예요.

OffGameInteractor에서는 LoggedIn RIB에게 본인은 이제 불필요졌다고 알려야해요.
OffGameListener protocol을 활용하면 LoggedInInteractor에게 알릴 수 있어요 !

– 우선 OffGameListener에 메소드를 추가하고, ViewController로부터 실행되는 메소드에서 추가한 메소드를 실행하도록 코드를 추가해주세요.


LoggedInInteractor에서는
RIB Tree를 구성하는 Router인 LoggedInRouterOffGame RIB 와의 연결을 끊도록 요청해야해요.

Router와 연결되어있는 LoggedInRouting에 메소드를 추가하고,
InteractorstartGame에서 추가한 메소드를 사용합니다.

– 마지막으로 !!!!!! RIB를 detach시키고 보여지는 VC도 dismiss 시켜주세요 !!!!!

이렇게 Start Game의 버튼 터치로 LoggedIn 으로 돌아오는 것까지의 구현이 완료되었어요 !

🔗 commit





4) (진짜 최종) LoggedIn 에서 TicTacToe 를 연결.

이건 Root RIB에서 LoggedOut RIB를 연결했을 때와 똑같은 흐름이기 때문에
commit 링크만 공유해둘게용 😀

🔗 commit




5. TicTacToe 게임이 끝나면,
TicTacToe RIB 를 분리시키고
OffGame RIB 를 연결시키기.


TicTacToe 게임이 끝났을 때 TicTacToe RIB를 분리시키고
LoggedIn 에 OffGame을 다시 연결시키는 코드를 실현해봅시다 ! 🦾

저는 TicTacToe 게임을 구현하지 않았어서
TicTacToeViewController에 Finish game 버튼을 추가하고
유저가 Finish game 버튼을 터치했을 때 게임이 끝났다는 전제로 구현할게요 🤫

1) TicTacToeViewController에 Finish Button 추가.

– 저는 Storyboard에서 추가하고, IBAction까지 추가했어요.
🔗 commit


2) 유저가 FinishGame을 터치했을 때 TicTacToe 를 분리시키고, LoggedIn RIB에 OffGame을 연결시키기.
– 흐름과 방법이 OffGame RIB -> LoggedIn RIB -> TicTacToe RIB 때오ㅏ 동일하고, 순서만 반대로 구현하면 할 수 있어요 💪
– 도전해보시고 잘 안풀리는 부분이 있으면 🔗 commit 을 참고해주셔요 ㅎ !




6. Unit Testing

저는 패스할게요 🙏
나중에 기회가 된다면 따로 쓸게여 !







코드도 넣고 링크도 넣다보니
너무너무 길어졌네요 😣

다음 글은
Player모델을 만들고 점수를 RxStream으로 구현하는 마지막 RIBs 글이에요 !


펭 빠 !
오늘도 즐거운 iOS 개발되세용

우니쿤의 All posts | 아프리카TV 방송국

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중