Представьте, что у меня есть фабрика контроллеров представления со следующим типом:
protocol ViewFactoryType {
associatedtype T
func create(for scene: T) -> UIViewController
}
final class ViewFactory<T>: ViewFactoryType {
func create(for scene: T) -> UIViewController {
return .init()
}
}
И у меня также есть навигационный маршрутизатор со следующим типом:
protocol RouterType {
associatedtype T
func navigate(to target: T, using transition: Transition)
}
Что бы я хотел сделать, это создать экземпляр RouterType
и передать его и экземпляр ViewFactory
.
Оба типа generi c T
фактически будут использовать тот же тип Scene
.
Я попытался создать этот маршрутизатор следующим образом:
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)
}
}
}
Однако это приводит к ошибке:
Protocol 'ViewFactoryType' can only be used as a generic constraint because it has Self or associated type requirements
и
Member 'create' cannot be used on value of protocol type 'ViewFactoryType'; use a generic constraint instead
Я смог немного обойти это, используя расширение:
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) {
}
}
Но фабричный метод не имеет правильного типа, если я добавлю его тоже func route(to target: Scene, as transition: Transition)