Je joue avec l'architecture MVVM-C, mais je ne sais pas comment je peux instancier plusieurs coordinateurs avec différents onglets lorsqu'un onglet est sélectionné.
Voici ma principale classe de coordinateur d'applications ...
protocol UINavigationControllerType: class {
func pushViewController(_ viewController: UIViewController, animated: Bool)
func popViewController(animated: Bool) -> UIViewController?
}
protocol Coordinator: class {
func start()
}
final class AppCoordinator: Coordinator {
// MARK: - Properties
var managedObjectContext: NSManagedObjectContext!
var coordinators = [String : Coordinator]()
var tabController: UITabBarController?
// MARK: - Object Lifecycle
init(moc: NSManagedObjectContext, tabController: UITabBarController) {
self.managedObjectContext = moc
self.tabController = tabController
}
// MARK: - Coordinator
func start() {
guard let tabController = tabController else {return}
let profileNavigationController = NavigationController()
profileNavigationController.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(named: "profileUnselected"), selectedImage: UIImage(named: "profileSelected"))
let plansNavigationController = NavigationController()
plansNavigationController.tabBarItem = UITabBarItem(title: "Plans", image: UIImage(named: "plansUnselected"), selectedImage: UIImage(named: "plansSelected"))
tabController.viewControllers = [profileNavigationController, plansNavigationController]
tabController.selectedViewController = profileNavigationController
let profileCoordinator = ProfileCoordinator(navigationController: profileNavigationController)
profileCoordinator.managedObjectContext = managedObjectContext
coordinators["profileCoordinator"] = profileCoordinator
profileCoordinator.delegate = self
profileCoordinator.start()
}
}
// MARK: - ProfileCoordinatorDelegate
extension AppCoordinator: ProfileCoordinatorDelegate {}
Alors, comment pourrais-je passer du coordinateur actuel (ProfileCoordinator) au PlansCoordinator lorsque l'onglet est sélectionné?
Ma structure de coordinateur est différente de la vôtre, mais elle pourrait vous aider. Dans mon cas, le protocole du coordinateur a une propriété rootViewController
qui pointe vers le ViewController de ce coordinateur.
Mon AppCoordinator
persiste alors un TabCoordinator
, qui ressemble un peu à ceci: (Dans le code réel, les coordinateurs persistants sont NavigationCoordinators
, qui sont des coordinateurs spéciaux qui contiennent NavigationControllers. Dans ce exemple, je viens d'ajouter les ViewControllers et de supprimer les éléments de gestion de la mémoire pour le rendre plus facile à comprendre.)
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
}
}
Donc, fondamentalement, votre TabBarController est un TabCoordinator dont le rootViewController
est un TabBarController. Le TabCoordinator instancie les coordinateurs appropriés et ajoute leurs rootViewControllers
respectifs à l'onglet.
Voici une implémentation de base de 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
}
}
Et une version de base d'un Coordinator
:
public protocol Coordinator: class {
var rootViewController: UIViewController { get }
}
Je veux partager un exemple pour cette question. Mon approche est un peu différente et TabCoordinator
ne contient pas tout dans son corps. Au lieu de cela, chaque coordinateur a une relation avec son contrôleur et dans chaque UIViewController
(dans le contrôleur de la barre de tabulation) a son UITabBarController
référence comme modèle de délégation.
class Coordinator {
var navigationController: UINavigationController?
var childCoordinators: [Coordinator] = [Coordinator]()
init(with navigation: UINavigationController) {
self.navigationController = navigation
}
func start() {}
}
Alors voici les coordinateurs.
Coordonnateur à domicile
final class HomeCoordinator: Coordinator {
var currentController: HomeController?
weak var tabController: TabController?
override init(with navigation: UINavigationController) {
super.init(with: navigation)
currentController = HomeController()
currentController?.coordinator = self
childCoordinators.append(self)
}
override func start() {
navigationController?.pushViewController(currentController ?? UIViewController(),
animated: true)
}
public func getHomeData() {
// GETTING HOME DATA
tabController?.requestFromHomeController()
}
}
À propos du coordinateur
final class AboutCoordinator: Coordinator {
var currentController: AboutController?
weak var tabController: TabController?
override init(with navigation: UINavigationController) {
super.init(with: navigation)
currentController = AboutController()
currentController?.coordinator = self
childCoordinators.append(self)
}
override func start() {
navigationController?.pushViewController(currentController ?? UIViewController(),
animated: true)
}
public func getAboutData() {
// GETTING ABOUT DATA
tabController?.requestFromAboutController()
}
}
UITabBarController
final class TabController: UITabBarController {
weak var coordinator: MainTabCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
let navigationController1 = UINavigationController()
let coordinator1 = HomeCoordinator(with: navigationController1)
coordinator1.tabController = self
coordinator1.currentController?.tabBarItem = UITabBarItem(title: "HOME",
image: nil,
tag: 11)
let navigationController2 = UINavigationController()
let coordinator2 = AboutCoordinator(with: navigationController2)
coordinator2.tabController = self
coordinator2.currentController?.tabBarItem = UITabBarItem(title: "ABOUT",
image: nil,
tag: 22)
viewControllers = [
coordinator1.currentController!,
coordinator2.currentController!
]
tabBar.barTintColor = UIColor.white
tabBar.isTranslucent = false
}
public func requestFromHomeController() {
print("Home Triggered the function")
coordinator?.fetchHome(with: "Simple Data",
completion: { (dictionary, error) in
print("dict from home -> ", dictionary)
})
}
public func requestFromAboutController() {
print("About Triggered the function")
coordinator?.handleAbout(with: "Simple Data",
completion: { (dictionary, error) in
print("dict from about -> ", dictionary)
})
}
}
Préparez l'application depuis AppDelegate
dans l'application (_ application: UIApplication, fonction didFinishLaunchingWithOptions
let appNavigationController = UINavigationController()
let tabCoordinator = MainTabCoordinator(with: appNavigationController ?? UINavigationController())
tabCoordinator.start()
window?.rootViewController = appNavigationController
Voici le AboutController
final class AboutController: UIViewController{
weak var coordinator: AboutCoordinator?
// define a button and add its target to handleButton function
@objc private func handleButton(_ sender: UIButton) {
coordinator?.getAboutData()
}
override func viewDidLoad() {
super.viewDidLoad()
// ui settings
}
}
MainTabCoordinator
final class MainTabCoordinator: Coordinator {
var currentController: TabController?
override init(with navigation: UINavigationController) {
super.init(with: navigation)
self.currentController = TabController()
self.childCoordinators.append(self)
currentController?.coordinator = self
}
override func start() {
navigationController?.pushViewController(currentController ?? UIViewController(),
animated: true)
}
func fetchHome(with title: String, completion: @escaping (_ result: Dictionary<String,Any>, _ error: NSError?) -> ()) {
completion(["ss":"ss"], nil)
}
func handleAbout(with title: String, completion: @escaping (_ result: Dictionary<String,Any>, _ error: NSError?) -> ()) {
completion(["ss":"ss"], nil)
}
}
Le schéma de travail est le suivant:
AboutController
---> action déclenchée ---> AboutCoordinator
---> TabBarController reference
a une requête sur l'action ----> MainTabCoordinator
handle fonctionne.