Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MVVM - Navigation Analysis #23

Closed
akayrak-adesso opened this issue May 29, 2020 · 2 comments
Closed

MVVM - Navigation Analysis #23

akayrak-adesso opened this issue May 29, 2020 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@akayrak-adesso
Copy link
Contributor

Navigation approaches and patterns in MVVM should be analyzed.

@kaanbiryol
Copy link

kaanbiryol commented Jun 12, 2020

Introduction

There are two main approaches for navigating between controllers. Coordinator and flow coordinators. Both of them have very abstract definitions therefore have very different implementations. Rather than explaining the abstract definitions of these patterns, I will share some basic implementations of these patterns just to give an idea of what they look like.

Coordinator

protocol Coordinator {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }
    func start()
}
class FirstCoordinator: Coordinator {
	//Used for holding sub-coordinators
    var childCoordinators = [Coordinator]()
    var navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        let controller = FirstViewController()
        controller.coordinator = self
        navigationController.pushViewController(controller, animated: false)
    }

    func route(with data: String) {
        let vc = SecondViewController()
        navigationController.pushViewController(vc, animated: false)
    }
}
class FirstViewController: UIViewController {
     weak var coordinator: FirstCoordinator?

    @IBAction func route(_ sender: Any) {
		coordinator?.route(with: "Data")
	}
}

Flow Coordinator

FlowCoordinator is basically the same pattern with the Coordinator expect for the one fact that the Coordinator itself is basically a UIViewController rather than some abstract Protocol.

class FirstFlowController: UIViewController {
    private let navigation = UINavigationController()

    override func viewDidLoad() {
        super.viewDidLoad()
        let firstViewController = FirstViewController()
        firstViewController.delegate = self
        navigation.show(firstViewController, sender: self)
        add(navigation)
    }
    
     func add(_ child: UIViewController) {
        addChild(child)
        view.addSubview(child.view)
        child.didMove(toParent: self)
    }
}

protocol FlowControllerDelegate {
    func route(with data: String)
}

extension FirstFlowController: FlowControllerDelegate {
    func route(with data: String) {
        let vc = SecondViewController()
        navigationController.pushViewController(vc, animated: false)
     }
}
class FirstViewController: UIViewController {
	weak var delegate: FlowControllerDelegate?

	@IBAction func route(_ sender: Any) {
		delegate?.route(with: "Data")
	}
}

There are few differences between these patterns but the one I found most important is syncing sub-coordinators with UINavigationController. Users can tap on the back button in UINavigationViewController and this would pop the current view controller out of the navigation stack but then we would need to tell our Parent-Coordinator somehow to remove child-coordinator from stack too. (see here)

There is a more detailed comparison of these two here.

@akayrak-adesso
Copy link
Contributor Author

Coordinator pattern will be used for navigation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
No open projects
Development

No branches or pull requests

2 participants