Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean Swift - Routing without segues

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

like image 762
Sazzad Hissain Khan Avatar asked Dec 24 '22 11:12

Sazzad Hissain Khan


1 Answers

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

like image 66
pacification Avatar answered Dec 28 '22 06:12

pacification