Imagine I have a view controller factory with the following type:
protocol ViewFactoryType {
associatedtype T
func create(for scene: T) -> UIViewController
}
final class ViewFactory<T>: ViewFactoryType {
func create(for scene: T) -> UIViewController {
return .init()
}
}
And I also have an navigation router with the following type:
protocol RouterType {
associatedtype T
func navigate(to target: T, using transition: Transition)
}
What I would like to do is create an instance of RouterType and pass it and instance of a ViewFactory.
Both generic T types will in fact use the same Scene type.
I have tried to create that router as follows:
final class AppRouter<T>: RouterType {
private let viewControllerFactory: ViewFactoryType
private let navigationController: UINavigationController
public init(navigationController: UINavigationController, viewControllerFactory: ViewFactoryType) {
self.navigationController = navigationController
self.viewControllerFactory = viewControllerFactory
}
public func navigate(to target: T, using transition: Transition) {
routeTo(viewControllerFactory.create(for: target), transition: transition)
}
private func routeTo(_ viewController: UIViewController, transition: Transition) {
switch transition {
case .push: navigationController.pushViewController(viewController, animated: true)
case .present: navigationController.present(viewController, animated: true)
case .replace: navigationController.setViewControllers([viewController], animated: false)
}
}
}
However this produces the error:
Protocol 'ViewFactoryType' can only be used as a generic constraint because it has Self or associated type requirements
and
Member 'create' cannot be used on value of protocol type 'ViewFactoryType'; use a generic constraint instead
I was able to get around this slightly by using an extension:
final class AppRouter<T> {
private let viewControllerFactory: ViewFactoryType
private let navigationController: UINavigationController
public init(navigationController: UINavigationController, viewControllerFactory: ViewFactoryType) {
self.navigationController = navigationController
self.viewControllerFactory = viewControllerFactory
}
private func routeTo(_ viewController: UIViewController, transition: Transition) {
switch transition {
case .push: navigationController.pushViewController(viewController, animated: true)
case .present: navigationController.present(viewController, animated: true)
case .replace: navigationController.setViewControllers([viewController], animated: false)
}
}
}
extension AppRouter: Router where T == Scene {
func route(to target: Scene, as transition: Transition) {
}
}
But the factory method does not have the correct type if I add it too func route(to target: Scene, as transition: Transition)