Ad

Clean Swift - Routing Without Segues

- 1 answer

I found Router in Clean Swift architecture is responsible to navigate and pass data from/to view controllers. Some samples and articles depicts that Routers use segues to pass and communicate with view controllers. What would be the convenience design when I don't want to use any segue from Storyboard. Isn't it possible to pass data without segue in Clean Swift? If you describe with simplest complete example I would appreciate.

Ad

Answer

Article says that you can:

// 2. Present another view controller programmatically

You can use this to manually create, configure and push viewController.

Example.

Let's pretend that you have ViewController with button (handle push):

final class ViewController: UIViewController {

    private var router: ViewControllerRouterInput!

    override func viewDidLoad() {
        super.viewDidLoad()

        router = ViewControllerRouter(viewController: self)
    }

    @IBAction func pushController(_ sender: UIButton) {
        router.navigateToPushedViewController(value: 1)
    }

}

This ViewController has router that implements ViewControllerRouterInput protocol.

protocol ViewControllerRouterInput {
    func navigateToPushedViewController(value: Int)
}

final class ViewControllerRouter: ViewControllerRouterInput {

    weak var viewController: ViewController?

    init(viewController: ViewController) {
        self.viewController = viewController
    }

    // MARK: - ViewControllerRouterInput

    func navigateToPushedViewController(value: Int) {
        let pushedViewController = PushedViewController.instantiate()
        pushedViewController.configure(viewModel: PushedViewModel(value: value))
        viewController?.navigationController?.pushViewController(pushedViewController, animated: true)
    }

}

The navigateToPushedViewController func can takes any parameter you want (it is good to encapsulate parameters before configure new vc, so you may want to do that).

And the PushedViewController hasn't any specific implementation. Just configure() method and assert (notify you about missing configure() call):

final class PushedViewModel {

    let value: Int

    init(value: Int) {
        self.value = value
    }

}

final class PushedViewController: UIViewController, StoryboardBased {

    @IBOutlet weak var label: UILabel!

    private var viewModel: PushedViewModel!

    func configure(viewModel: PushedViewModel) {
        self.viewModel = viewModel
    }

    override func viewDidLoad() {
        super.viewDIViewController, StoryboardBased {

    @IBOutlet weak var label: UILabel!

    private var viewModel: PushedViewModel!

    func configure(viewModel: PushedViewModel) {
        self.viewModel = viewModel
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        assert(viewModel != nil, "viewModel is nil. You should call configure method before push vc.")

        label.text = "Pushed View Controller with value: \(viewModel.value)"
    }

}

Note: also, i used Reusable pod to reduce boilerplate code.

Result:

enter image description here

Ad
source: stackoverflow.com
Ad