Back button not being called in TabbarCoordinator in horizontal flow iOS 12

血红的双手。 提交于 2020-01-16 10:11:48

问题


Coordinator pattern is an old topic with many libraries trying to solve it and I am learning it in simple example app. My current set up is 3 rootViewControlers: LoadingStateCoordinator, WelcomeCoordinator, TabBarCoordinator but missing connection between UIKit and coordinators. I am trying to implement it with a UINavigationController but the button is not being called. I need a way to connect to back button and a reusable coordinator that I could push to and dellocate accordingly (that is without RxSwift).*Set up Welcome screen as the parent/main navigation and always be able to come back to it.** So after user selects a form from modal view (vertical flow) presented I show on a push a TabBarCoordinator (horizontal). All viewControllers have empty.storyboard, UIViewController and Coordinator exept the TabBar.Here I only have a coordinator due to the set up of child tab coordinators and the magic needs to happen on a back button tap. Currenly this only being called when user comes from LoadingStateCoordinator. There I need to send the user back to the Welcome screen so they can change the onboarding set up. Here is the first code for LoadingStateCoordinator:

final class LoadingStateCoordinator: NSObject, Coordinator {
    *// MARK: - Inputs required*

    var childCoordinators: [Coordinator]
    var presenter: UINavigationController
    private let window: UIWindow

    *// MARK: - Initialization*
    init(window: UIWindow) {
        self.window = window
        childCoordinators = []
        presenter = UINavigationController()
    }
    *// MARK: - Coordinator*
     func start() {
        let controller: LoadingStateViewController = LoadingStateViewController.instantiate()
        window.rootViewController = controller
        controller.delegate = self
        }

}
    *// MARK: - LoadingViewControllerDelegate*
extension LoadingStateCoordinator : LoadingViewControllerDelegate {
    func performScreenSwitch() {
        if UserDefaults.standard.userWasHere == false {
            let tabCoordinator: TabBarCoordinator = TabBarCoordinator(window: window, tabBarController: UITabBarController())
            window.rootViewController = presenter
            addChildCoordinator(tabCoordinator)
            tabCoordinator.start()
            presenter.pushViewController(tabCoordinator.tabBarController!, animated: true)

        } else {
            let welcomeCoordinator = WelcomeCoordinator(window: window, presenter: presenter)
            window.rootViewController = welcomeCoordinator.presenter
            addChildCoordinator(welcomeCoordinator)
            welcomeCoordinator.start()
        }
    }
}

And here is the TabBarCoordinator that need to perform back to Welcome screen action. When I present popToRootfunction it pushes the Welcome screen but all the button there are disbled. I guess to be retain cycle issue. Do I need funadametally another set up? Is there a way to popToRoot(vc) in this set up? What I tryed ended with runtime error "poping to non existing controller". TabBarCoordinator code that need to perform this:

final class TabBarCoordinator: NSObject, Coordinator {
    internal var presenter: UINavigationController
    internal var tabBarController: UITabBarController?
    internal var childCoordinators: [Coordinator]
    var parentCoordinator: LoadingStateCoordinator?
    lazy var leftBtn: UIBarButtonItem = {
        let button = UIButton(type: .system)
        button.setImage(UIImage(systemName: "arrow.turn.up.left"), for: .normal)
        button.sizeToFit()
        button.addTarget(self,
                         action: #selector(self.popToRoot(_:)),
                         for: .touchUpInside)
      return UIBarButtonItem(customView: button)
    }()

    init(window: UIWindow, tabBarController: UITabBarController) {
        self.tabBarController = tabBarController
        childCoordinators = []
        self.presenter = UINavigationController()

    }
     func start() {
        performGetTabBar()
        self.presenter.delegate = self
    }
    private func performGetTabBar() {
        let coordinators: [Coordinator] = generateTabCoordinators()

        coordinators.forEach({ coordinator in
            coordinator.start()
            addChildCoordinator(coordinator)
        })

        let presenters: [UIViewController] = coordinators.map({ coordinator -> UIViewController in
            return coordinator.presenter
        })
        leftBtn.style = .plain
        tabBarController?.navigationItem.leftBarButtonItem = leftBtn
        tabBarController?.setViewControllers(presenters, animated: false)
        selectTab(type: SurfTripCoordinator.self)
    }

    private func generateTabCoordinators() -> [Coordinator] {
        let calculatorCoordinator: CalculatorCoordinator = CalculatorCoordinator(presenter: UINavigationController())
        let tripCoordinator: SurfTripCoordinator = SurfTripCoordinator(presenter: UINavigationController())
        let sellCoordinator: SavedTripsCoordinator = SavedTripsCoordinator(presenter: UINavigationController())
        return [calculatorCoordinator, tripCoordinator, sellCoordinator]
    }
    *//this is not being called when coming from vertical flow*
    @objc func popToRoot(_ sender: UIBarButtonItem) {
        let storyboard: UIStoryboard = UIStoryboard(name: Constants.Storyboards.welcomeViewCoordinator, bundle: nil)
        let controller: WelcomeViewController = WelcomeViewController.instantiate(from: storyboard)
        tabBarController?.navigationController?.pushViewController(controller, animated: true)

    }
}

extension TabBarCoordinator: UINavigationControllerDelegate {

    func selectTab<T: Coordinator>(type _: T.Type) {
        guard let index = childCoordinators.firstIndex(where: { coordinator in
            coordinator is T
        }) else {
            return
        }
        tabBarController?.selectedIndex = index
  }
}

and here is the current WelcomeCoordinator set up

class WelcomeCoordinator: NSObject, Coordinator {
    internal var presenter: UINavigationController
    var childCoordinators: [Coordinator]

    init(window: UIWindow, presenter: UINavigationController) {
        self.presenter = presenter
        childCoordinators = []

    }
    func start() {
        let storyboard: UIStoryboard = UIStoryboard(name: Constants.Storyboards.welcomeViewCoordinator, bundle: nil)
        let controller: WelcomeViewController = WelcomeViewController.instantiate(from: storyboard)
        controller.delegate = self
        presenter.pushViewController(controller, animated: true)
    }
}

extension WelcomeCoordinator : WelcomeViewControllerDelegate {

    func performAddLevel() {
        let addLevelCoordinator: AddLevelViewCoordinator = AddLevelViewCoordinator(presenter: UINavigationController())
        addLevelCoordinator.start()
        addChildCoordinator(addLevelCoordinator)
        addLevelCoordinator.presenter.modalPresentationStyle = .fullScreen
        presenter.present(addLevelCoordinator.presenter, animated: true, completion: nil)
    }
}

sorry for the long post I wish there was more reaktive native way to do this...


回答1:


Ok so I found partlly a solution the back button solution for my case: not using pushViewController or show because it comes with back button. presenter.setViewControllers([tabCoordinator.tabBarController!], animated: true) and there setting the navBar to hidden. I made my own navItem button to navigate to rootVC. Next step to allocate and remove all child tabBar coordinators on back tap recognized.



来源:https://stackoverflow.com/questions/59486627/back-button-not-being-called-in-tabbarcoordinator-in-horizontal-flow-ios-12

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!