-
[iOS] RIBs 로 Routing 처리 #2👻 iOS 2021. 1. 16. 00:56
2021/01/15 - [👻 iOS] - [iOS] RIBs 로 Routing 처리 #1 에서 이어집니다.
이전까지 Todo RIB을 구성하고
Root 에서 해당 RIB을 떼었다가 붙이거나 하는 구현을 마쳤어요.
이제 LoggedOut RIB 에서 Todo RIB 으로 넘어가는 구현을 알아 보겠습니다.
(뷰를 코드로 좀 더 수월하게 구성하기 위해서 SnapKit 을 Podfile에 추가)
LoggedOut에 버튼 하나 넣어주고.
버튼을 누르면 RootRouter에 routeToTodo 가 불려지면 되겠습니다.
그렇다면 아래와 같은 과정이 필요할듯 해요.
1. LoggedOutViewController 에서 listener 를 호출하는 것으로 정의하고
2. interactor 에서는 해당 프로토콜을 구현해주고 ,
3. RootInteractor로 의도를 전달해주고,
4. RootRouter는 routerToTodo를 불러서 RIB을 바꾼다!
시작해 봅니다.
ViewController에서 interactor로 호출을 위해 LoggedOutPresentableListener 에 login 선언을 해줍니다.
그리고 빌드!
protocol LoggedOutPresentableListener: class { func login() // 이름이 LoggedOut 이니까 화면을 바꾸는건 login 이겠지? }
빌드하면 구현이 필요한 곳에 오류가 나요. 그게 LoggedOutInteractor가 되겠고요.
login이 불려지면 부모의 interactor로 의도를 전달해 줍니다. listener가 여기에선 Root가 대상이 되겠네요.
다시 빌드를 눌러줍니다.
protocol LoggedOutListener: class { func routeToTodo() } final class LoggedOutInteractor: PresentableInteractor<LoggedOutPresentable>, LoggedOutInteractable, LoggedOutPresentableListener { .... func login() { // 가정) 어쩌구 저쩌구 로그인 처리가 다 됐다고 치면 // TODO로 이동하자. listener?.routeToTodo() } }
오류가 발생하는 곳은 예상대로 RootInteractor
routeToTodo 의 내부에선 router를 이용해서 RIB을 바꾸는게 목적이니
router의 protocol을 구현해 아래와 같이 선언해 줍니다.
그리고 또 빌드!
protocol RootRouting: ViewableRouting { func routeToTodo() func routeToLoggedOut() } final class RootInteractor: PresentableInteractor<RootPresentable>, RootInteractable, RootPresentableListener { .... func routeToTodo() { router?.routeToTodo() } }
이전에 RootRouter에 routerToTodo와 routerToLoggedOut 을 구현해 두었기 때문에
별다른 오류는 발생하지 않아요 ㅋㅋ 다행!
여기까지 했으면 로직은 완성으로 보고
LoggedOutViewController 에서 버튼을 만들어 봅니다.
import SnapKit import RxCocoa ... final class LoggedOutViewController: UIViewController, LoggedOutPresentable, LoggedOutViewControllable { weak var listener: LoggedOutPresentableListener? lazy var disposeBag = DisposeBag() override func viewDidLoad() { self.view.backgroundColor = .green let button = UIButton() self.view.addSubview(button) button.setTitle("TODO로 이동하기", for: .normal) button.backgroundColor = .white button.setTitleColor(.black, for: .normal) button.snp.makeConstraints { (maker) in maker.width.height.equalTo(150) maker.center.equalToSuperview() } button.rx.tap .subscribe(onNext: { [weak self] _ in self?.listener?.login() }) .disposed(by: disposeBag) } }
SnapKit과 RxCocoa 를 import 했어요. (RxCocoa는 Podfile에 빠져 있어서 추가했습니다)
그럼 대충 이런 모양이 되요.
구현에도 있지만 listener.login을 호출하게 됩니다.
디자이너가 보면 혼절할 화면 대망의 버튼 클릭을 하면 화면이 이동하면서 끝~!!
인줄 알았으나 오류.
털썩.....
[Presentation] Attempt to present <rib_test.TodoViewController: 0x7fdcf9505cb0> on <rib_test.RootViewController: 0x7fdcf9509410> (from <rib_test.RootViewController: 0x7fdcf9509410>) which is already presenting <rib_test.LoggedOutViewController: 0x7fdcfc00a3a0>. Assertion failed: <<rib_test.LoggedOutViewController: 0x7fdcfc00a3a0>: -485640791687519794> has leaked. Objects are expected to be deallocated at this time: NSMapTable { [5] -485640791687519794 -> <rib_test.LoggedOutViewController: 0x7fdcfc00a3a0> } : file RIBs/LeakDetector.swift, line 102 Assertion failed: <<rib_test.LoggedOutViewController: 0x7fdcfc00a3a0>: -485640791687519794> has leaked. Objects are expected to be deallocated at this time: NSMapTable { [5] -485640791687519794 -> <rib_test.LoggedOutViewController: 0x7fdcfc00a3a0> } : file RIBs/LeakDetector.swift, line 102
이것은 무엇인고...
오류 내용을 보아하니 LoggedOut이 있는데 Todo를 꼿아 넣은 것이 오류 원인이네요.
detach를 제대로 못시켰나 확인해 봅니다.
RootViewController의 구현에 presentedViewController 대신 presentingViewController 를 사용했던게 오류의 원인이었어요.
후.. 잊고 있었따...
{ func dismiss(viewControllable: ViewControllable) { // 오류가 발생했던 코드 // if presentingViewController === viewControllable.uiviewController { // dismiss(animated: true, completion: nil) // } // 정상동작 코드 if presentedViewController === viewControllable.uiviewController { dismiss(animated: true, completion: nil) } } }
이렇게 오류까지 고쳐주면 정상동작 확인~!
git : github.com/maarteti/rib-test/tree/todo-step2
maarteti/rib-test
Contribute to maarteti/rib-test development by creating an account on GitHub.
github.com