천원의 개발

Swift RIBs 튜토리얼 (with StoryBorad) 본문

iOS&Swift🍎/Swift

Swift RIBs 튜토리얼 (with StoryBorad)

천 원 2023. 8. 26. 21:07

안녕하세요. 천원입니다.

RIBs 튜토리얼 진행하면서 상당히 바보같은 코드를 작성해서 반성 하고자 글을 작성해봅니다.

 

튜토리얼

튜토리얼을 진행하기 전에 우선 Root를 RIB을 직접 구현해서 LoggedOut RIB을 attach 시켜주고 진행을 하였습니다.

그리구 튜토리얼에서는 SnapKit을 사용해서  UI를 구성해주는데 저는 StoryBoard로 아래와 같이 구성하였습니다.

 

 

먼저 LogOut Button을 눌렀을때 실행하려는 함수를 LoggedOutPresentableListener 프로토콜에 선언 해주었구요.

protocol LoggedOutPresentableListener: AnyObject {
    func logOut(id: String, pw: String)
}

 

그런 다음 LoggedOutPresentableListener을 채택한 LoggedOutInteractor 내부에 logOut 메서드를 작성 해주었습니다.

final class LoggedOutInteractor: PresentableInteractor<LoggedOutPresentable>, LoggedOutInteractable, LoggedOutPresentableListener {

    weak var router: LoggedOutRouting?
    weak var listener: LoggedOutListener?

    // TODO: Add additional dependencies to constructor. Do not perform any logic
    // in constructor.
    override init(presenter: LoggedOutPresentable) {
        super.init(presenter: presenter)
        presenter.listener = self
    }

    override func didBecomeActive() {
        super.didBecomeActive()
        // TODO: Implement business logic here.
    }

    override func willResignActive() {
        super.willResignActive()
        // TODO: Pause any business logic.
    }
    
    func logOut(id: String, pw: String) {
        print("ID: \(id) PW: \(pw)")
    }
}

 

 

이제 LoggedOutPresentableListener를 타입으로 가지는 ViewContoller의 listener 변수를 활용해서 호출하면 정상적으로 동작하겠다. delegate 패턴이랑 상당히 유사한 모습이라고 생각했습니다.

@IBAction func logOutTap(_ sender: UIButton) {
    listener?.logOut(id: idTF.text!, pw: pwTF.text!)
}

 

그러구 로그아웃 버튼을 눌렀는데 Interactor 내부에 logOut을 호출이 안됐습니다.. 이유를 찾아보니 listener가 nil 값으로 들어오고 있더라구요 그래서 혹시 내가 LoggedOut Builder에서 인스턴스 생성을 잘못했나..? RootRouter에서 attach를 잘못했나!?!? 하고 한참을 찾고 있었는데 정말 바보같은 실수를 했더라구요. 

 

기존에 Root RIB에서 다른 ViewContoller present 하는 코드는 아래와 같았고 

protocol RootViewControllable: ViewControllable {
    func present(viewController: ViewControllable)
}

// MARK: - RootViewController
func present(viewController: ViewControllable) {
    present(viewController.uiviewController, animated: true, completion: nil)
}

 

저는 스토리보드를 사용해서 StoryBoard로 한번 감싸주는 코드를 아래처럼 작성했습니다.

protocol RootViewControllable: ViewControllable {
    func present<T: UIViewController>(viewController: ViewControllable, from: T.Type)
}

func present<T: UIViewController>(viewController: ViewControllable, from: T.Type) {
    let sb = UIStoryboard(name: "loggedOut", bundle: nil)
    let vc = sb.instantiateViewController(withIdentifier: String(describing: type(of: viewController.uiviewController))) as! T
    vc.modalPresentationStyle = .fullScreen

    self.present(vc, animated: true, completion: nil)
}

 

다들 눈치채셨나요..? 여기서 viewContoller 매개변수는 Router에서 LoggedOut Builder가 build(withListener: ) 메서드로 listener를 넣어서 보내준 인스턴스인데.. 그걸 또 새로운 LoggedOutViewContoller 인스턴스로 바꿔서.. present 하고있어서 listener가 nil 값으로 떨어졌습니다. 

 

 

그래서 present 코드를 기존 튜토리얼 Root RIB으로 수정하고 자신의 인스턴스를 생성하는 LoggedOutBuilder에 Build 메서드를 아래와 같이 수정해주었습니다.

func build(withListener listener: LoggedOutListener) -> LoggedOutRouting {
    let component = LoggedOutComponent(dependency: dependency)

    let sb = UIStoryboard(name: "loggedOut", bundle: nil)
    let vc = sb.instantiateViewController(identifier: "LoggedOutViewController") as! LoggedOutViewController

    let interactor = LoggedOutInteractor(presenter: vc)
    interactor.listener = listener
    return LoggedOutRouter(interactor: interactor, viewController: vc)
}

 

 

 

바보 같은 실수 덕분에 RIBs 파일들을 요목조목.. 뜯어보면서 처음 사용할 때보다는 어떤 방식으로 동작하는지 이해하는 데 도움이 된 것 같아서 정리할 겸 포스팅해 봅니다.

 

전체코드: https://github.com/Yoon-hub/Ribs_Pracitce

진짜 마음대로 정리한 tutorial: https://keen-name-701.notion.site/RIBs-857c2bf8e9ae427caa6958d8380b1bdb?pvs=4 

 

'iOS&Swift🍎 > Swift' 카테고리의 다른 글

iOS Tuist 프로젝트에 적용하기  (0) 2023.10.22
Swift RIBs RootRIB 설정하기  (0) 2023.09.09
Swift Adapter  (0) 2023.08.11
Swift RIBs  (0) 2023.07.27
Swift 전처리문 (#if Debug #endif)  (0) 2023.05.16