Home > Enterprise >  How to fix problem with opening ViewController by action from Coordinator in Swift?
How to fix problem with opening ViewController by action from Coordinator in Swift?

Time:05-14

I'm trying to open another controller by tapping on the cell of my tableView. I'm coding with MVVM and Coordinator pattern.

In the beginning we see this screen - it is declarated in the method start()

let service = Service()
private(set) weak var navigationController: UINavigationController?

func start() -> UINavigationController {
    let vm = ContinentsViewModel(service: service)
    let vc = ContinentsViewController(viewModel: vm)
    let navigationController = UINavigationController()
    self.navigationController = navigationController
    navigationController.setViewControllers([vc], animated: false)
    bindContinentsViewModel(viewModel: vm)
    return navigationController
}

pic.1 - func start()

Later, my goal is to open all list of countries of the continent, but now l just need to open empty ViewController by tap on the cell (ex. Africa or Antarctica). Here is my methods for it, but they don't work.

private func showCountries() {
    let vc = ViewController()
    navigationController?.pushViewController(vc, animated: true)
}

private func bindContinentsViewModel(viewModel: ContinentsViewModel) {
    viewModel
        .flow
        .bind { [weak self] flow in
            switch flow {
            case .onContinentTap:
                self?.showCountries() // don't work
              //  print("show \(continent)") // work - continent is a param of .onContinentTap, which prints an geo-id of the continent, just if you need to know.
            }
        }
        .disposed(by: viewModel.bag)
}

Thank you so much!

CodePudding user response:

The following works as expected. What are you doing differently?

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    var viewModel: ViewModel?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        viewModel = ViewModel()
        let controller = viewModel?.start()

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = controller
        window?.makeKeyAndVisible()

        return true
    }
}

final class ViewModel {
    private(set) weak var navigationController: UINavigationController?

    func start() -> UINavigationController {
        let vm = ContinentsViewModel()
        let vc = ContinentsViewController(viewModel: vm)
        let navigationController = UINavigationController()
        self.navigationController = navigationController
        navigationController.setViewControllers([vc], animated: false)
        bindContinentsViewModel(viewModel: vm)
        return navigationController
    }

    private func showCountries() {
        let vc = UIViewController()
        vc.view.backgroundColor = .blue
        navigationController?.pushViewController(vc, animated: true)
    }

    private func bindContinentsViewModel(viewModel: ContinentsViewModel) {
        viewModel.flow
            .bind { [weak self] flow in
                switch flow {
                case .onContinentTap:
                    self?.showCountries()
                }
            }
            .disposed(by: viewModel.bag)
    }
}

final class ContinentsViewModel {
    enum Flow {
        case onContinentTap
    }
    let flow: Observable<Flow>
    let bag = DisposeBag()

    init() {
        flow = .just(.onContinentTap)
            .delay(.seconds(3), scheduler: MainScheduler.instance)
    }
}

final class ContinentsViewController: UIViewController {
    var viewModel: ContinentsViewModel
    init(viewModel: ContinentsViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
    }
}

  • Related