Clean Swift - Routing Without Segues
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.
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:
Related Questions
- → Function Undefined in Axios promise
- → What are the pluses/minuses of different ways to configure GPIOs on the Beaglebone Black?
- → Click to navigate on mobile devices
- → Playing Video - Server is not correctly configured - 12939
- → How to allow api access to android or ios app only(laravel)?
- → Axios array map callback
- → Access the Camera and CameraRoll on Android using React Native?
- → Update React [Native] View on Day Change
- → Shopify iOS SDK - issue converting BuyProductVariant to BuyProduct
- → BigCommerce and shopify API
- → Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView`
- → React Native - Differences between Android and IOS
- → What is the difference between React Native and React?