'How to fix problem with opening ViewController by action from Coordinator in Swift?

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!



Solution 1:[1]

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
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Daniel T.