How to fix problem with opening ViewController by action from Coordinator in Swift?
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
}
}
How do i use coordinators with a UIITabBarController?
My Coordinator structure is a different than yours, but it might help you. In my case, the Coordinator protocol has a rootViewController
property which points to that Coordinator's ViewController.
My AppCoordinator
then persists a TabCoordinator
, which looks somewhat like this: (In the real code, the persisted coordinators are NavigationCoordinators
, which are special Coordinators that hold NavigationControllers. In this example I just added the ViewControllers and removed memory management stuff to make it easier to understand.)
final class TabCoordinator: NSObject, Coordinator {
var rootViewController: UIViewController {
return tabController
}
let tabController: UITabBarController
let homeCoordinator: HomeCoordinator
let historyCoordinator: HistoryCoordinator
let profileCoordinator: ProfileCoordinator
var coordinators: [Coordinator] {
return [homeCoordinator, historyCoordinator, profileCoordinator]
}
init(client: HTTPClient, persistence: Persistence) {
tabController = UITabBarController()
homeCoordinator = HomeCoordinator(client: client, persistence: persistence)
historyCoordinator = HistoryCoordinator(client: client, persistence: persistence)
profileCoordinator = ProfileCoordinator(client: client, persistence: persistence)
var controllers: [UIViewController] = []
let homeViewController = homeCoordinator.rootViewController
homeViewController.tabBarItem = UITabBarItem(title: Localization.homeTab.string, image: Asset.iconMenuRecharge.image, selectedImage: Asset.iconMenuRechargeActivated.image)
let historyViewController = historyCoordinator.rootViewController
historyViewController.tabBarItem = UITabBarItem(title: Localization.walletTab.string, image: Asset.iconMenuWallet.image, selectedImage: Asset.iconMenuWalletActivated.image)
let profileViewController = profileCoordinator.rootViewController
profileViewController.tabBarItem = UITabBarItem(title: Localization.profileTab.string, image: Asset.iconMenuProfile.image, selectedImage: Asset.iconMenuProfileActivated.image)
super.init()
controllers.append(homeViewController)
controllers.append(historyViewController)
controllers.append(profileViewController)
tabController.viewControllers = controllers
tabController.tabBar.isTranslucent = false
tabController.delegate = self
}
}
So basically, your TabBarController is a TabCoordinator whose's rootViewController
is a TabBarController. The TabCoordinator instantiates the relevant Coordinators and add their respective rootViewControllers
to the tab.
Here's a basic implementation of the NavigationCoordinator
:
class NavigationCoordinator: NSObject, Coordinator {
public var navigationController: UINavigationController
public override init() {
self.navigationController = UINavigationController()
self.navigationController.view.backgroundColor = .white
super.init()
}
public var rootViewController: UIViewController {
return navigationController
}
}
And a basic version of a Coordinator
:
public protocol Coordinator: class {
var rootViewController: UIViewController { get }
}
Related Topics
How to Stretch a View to Its Parent Frame with Swiftui
Swift 4 JSONdecoder Optional Variable
Swift Equivalent of Unity3D Coroutines
Parsing JSON from Url Ends Up with an Error - Swift 5
Error Domain=Nscocoaerrordomain Code=3840 "Invalid Value Around Character 0
Swift Equivalent of Objective-C for Flutter Native Ads
How to Navigate from Initial UIviewcontroller to UIsplitviewcontroller in Swift
Firebase Swift 3 Get List of Child in a Array
How to Save Re-Ordered Tableview Cells to Core Data
How to Get Address in English Language Only Using Gmsgeocoder
Occasional Blank Frames After Exporting Asset - Avexportsession
Non-Translucent UItabbar Creates Strange Grey Bar
Create Custom Action in a Class for Use in Interface Builder
How to Delay a Return-Statement in Swift
Secidentity + Force Cast Violation: Force Casts Should Be Avoided. (Force_Cast)
Error Combining Nscalendarunit with or (Pipe) in Swift 2.0
Calling C++ from Swift - What Is The Equivalent of Std::Vector<T>