-
RxFlow 적용기개발/Swift 2021. 5. 25. 17:44
우선 프로젝트에서 적용 시킨 Flow 는 이렇다
AppFlow → MainFlow
AppInitViewController 에서 init 함수들이 돌고 끝이나면
MainFlow 로 넘어가서 MainViewController 를 push 하고
MainViewController 에서 버튼을 클릭하면 CodingViewController 를 push 한다.
따라서 Step은 이렇게 단순하다.
enum AppStep: Step { case introIsRequired case mainIsRequired case codingIsRequired }
Flow의 시작은 SceneDelegate에서 시작해줬다.
let appFlow = AppFlow() let appStepper = OneStepper(withSingleStep: AppStep.introIsRequired) self.coordinator.coordinate(flow: appFlow, with: appStepper) Flows.use(appFlow, when: .created) { (root) in window.rootViewController = root window.makeKeyAndVisible() }
AppFlow를 사용하고 OneStepper를 넣어줘서 AppFlow이 시작하면서 introIsRequired 스텝이 처음으로 들어온다. Flows.use를 시작하여 AppFlow를 시작해준다.
이때 rootViewController를 변경해준다. Root는 AppFlow에서 지정해준다.
AppFlow에서는 UINavigationController를 생성해주고 root로 지정해준다.
var root: Presentable { return self.rootViewController } private lazy var rootViewController: UINavigationController = { let viewController = UINavigationController() viewController.setNavigationBarHidden(true, animated: false) return viewController }()
이렇게 함으로써 AppFlow를 시작했던 SceneDelegate에서
window.rootViewController를 AppFlow.rootViewController 로 변경해준것이다.
AppFlow에서는 두가지 navigate가 있다. introIsRequired mainIsRequired
introIsRequired 는 단순히 storyboard 를 불러와서 push 할것이고
mainIsRequired는 MainFlow로 변경할것이다.
func navigate(to step: Step) -> FlowContributors { guard let step = step as? AppStep else { return .none } switch step { case .mainIsRequired: return navigateToMainViewController() case .introIsRequired: return navigateToIntroController() default: return .none } }
introIsRequired
private func navigateToIntroController() -> FlowContributors { let storyboard = UIStoryboard(name: "Main", bundle: nil) let viewController = storyboard.instantiateViewController(withIdentifier: "Main") as! AppInitViewController self.rootViewController.pushViewController(viewController, animated: false) return .one(flowContributor: .contribute(withNext: viewController)) }
storyboard의 이름은 실제 storyboard 파일명이고 withIdentifier 는 storyboard안에 identifier이다.
현재는 AppFlow → introIsRequired
mainIsRequired
private func navigateToMainViewController() -> FlowContributors { let flow = MainScreenFlow(root: self.rootViewController) let nextStep = OneStepper(withSingleStep: AppStep.mainIsRequired) return .one(flowContributor: .contribute(withNextPresentable: flow, withNextStepper: nextStep)) }
private func navigateToMainViewController() -> FlowContributors { let flow = MainScreenFlow(root: self.rootViewController) let nextStep = OneStepper(withSingleStep: AppStep.mainIsRequired) return .one(flowContributor: .contribute(withNextPresentable: flow, withNextStepper: nextStep)) }
SceneDelegate에서 사용했듯이 flow와 step을 리턴해줬다.
하지만 여기서 pushViewController 를 사용하지 않음을 볼수있다.
RxFlow 예제 샘플코드 에서는 위의 경우처럼 다른 플로우를 사용할때 (갈아탈때?)
pushViewController 나 present를 사용했었다.
RxFlow 샘플코드
private func navigationToDashboardScreen() -> FlowContributors { let dashboardFlow = DashboardFlow(withServices: self.services) Flows.use(dashboardFlow, when: .created) { [unowned self] root in self.rootViewController.pushViewController(root, animated: false) } return .one(flowContributor: .contribute( withNextPresentable: dashboardFlow, withNextStepper: OneStepper( withSingleStep: DemoStep.dashboardIsRequired))) }
private func navigationToDashboardScreen() -> FlowContributors { let dashboardFlow = DashboardFlow(withServices: self.services) Flows.use(dashboardFlow, when: .created) { [unowned self] root in self.rootViewController.pushViewController(root, animated: false) } return .one(flowContributor: .contribute( withNextPresentable: dashboardFlow, withNextStepper: OneStepper( withSingleStep: DemoStep.dashboardIsRequired))) }
하지만 실제로 내 코드에서는 pushViewController를 하면 에러가 발생한다.
현재 rootViewController는 UINavigationController이고 (AppFlow의 rootViewController)
pushViewController 할 root 또한(MainFlow 의 rootViewController)
UINavigationController 이기 때문이다.
UINavigationController push UINavigationController = 에러
present는 화면의 크기가 크게 벗어나고 화면에 보여지는 문제가 있었다.
방법을 찾던중 rootViewController를 MainFlow 를 init 할때 MainFlow의 root로 넘겨주는방법을 선택했다.
class MainScreenFlow: Flow { var root: Presentable { return rootViewController } init(root:UINavigationController) { self.rootViewController = root } private let rootViewController : UINavigationController!
이방법을 통해 문제를 해결할수 있었다.
MainFlow 에서는 단순히 Storyboard를 불러와서 push해주면된다.
private func navigateToMainScreen() -> FlowContributors { let viewModel = inject(service: AppSettingViewModel.self) let storyboard = UIStoryboard(name: "Main", bundle: nil) guard let viewController = storyboard.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController else {return .none} self.rootViewController.pushViewController(viewController, animated: false) return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: viewModel as! Stepper)) }
'개발 > Swift' 카테고리의 다른 글
expandable + dynamic height tableview cell 구현하기 (0) 2021.09.02 Realm swift struct 타입, List타입 수정 하는법 (0) 2021.08.03 Swift 커스텀뷰 만들어서 재사용하기 (UIButton) (3) 2021.04.22 Swift Fastlane + SwiftLint + GitlabCI 연동하기 (0) 2021.04.09 Appstore 없이 Xcode 설치하는법 (0) 2021.04.09