Создание разделенного маршрутизатора и ViewFactory - PullRequest
4 голосов
/ 04 марта 2020

Я экспериментирую с маршрутизацией в приложении iOS.

Мой текущий подход натолкнулся на препятствие, однако я создаю ViewControllerFactory и NavigationControllerRouter.

Задача, с которой я столкнулся, заключается в том, что ViewControllerFactory необходимо указать маршрутизатору, какой маршрут требуется затем, а NavigationControllerRouter требует, чтобы фабрика передала контроллер представления в контроллер навигации.

Как могут эти 2 компонента общаться без создания сильной связи?

enum Route {
  case login
  case home
}

protocol ViewControllerFactory {
  func create(for route: Route) -> UIViewController
}

class VCFactory: ViewControllerFactory {
  func create(for route: Route) -> UIViewController {
    switch route {
    case .login:
      let viewController = UIViewController()
      viewController.view.backgroundColor = .purple
      return viewController
    case .home:
      let viewController = UIViewController()
      viewController.view.backgroundColor = .red
      return viewController
    }
  }
}

class NavigationControllerRouter {
  private let navigationController: UINavigationController
  private let factory: ViewControllerFactory

  init(_ navigationController: UINavigationController, factory: ViewControllerFactory) {
    self.navigationController = navigationController
    self.factory = factory
  }

  func route(to route: Route) {
    let viewController = factory.create(for: route)
    navigationController.pushViewController(viewController, animated: true)
  }
}

Я настроил это следующим образом

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

  var window: UIWindow?

  private lazy var navController = UINavigationController()
  private lazy var router: NavigationControllerRouter = {
    let viewControllerFactory = VCFactory()
    return NavigationControllerRouter(navController, factory: viewControllerFactory)
  }()

  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let scene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: scene)
    configure(window)
  }

  func configure(_ window: UIWindow) {
    self.window = window
    self.window?.makeKeyAndVisible()
    self.window?.rootViewController = navController

    router.route(to: .login)
  }
}

Я рассмотрел передачу слабой ссылки для маршрутизатора на фабрику контроллера представления, а затем внедрил это в любые визуализированные представления, однако это затем объединяет 2, особенно если я решу использовать фабрику представлений для чего-то вроде дочерних представлений, которые вообще не должны знать о маршрутизаторе.

1 Ответ

0 голосов
/ 04 марта 2020

Я не вижу ничего плохого в передаче ссылки на ваш VCFactory, при условии, что это слабый реф, чтобы гарантировать отсутствие циклов сохранения.

Это почти то же самое шаблон, используемый в подходе MVP, когда представление имеет ссылку на докладчика, а докладчик ссылается на представление.

Вы можете убедиться, что ваш ViewControllerFactory не содержит неиспользуемых ссылок на маршрутизатор, возможно, используя протокол для его расширения.

protocol Routable {
  var router: NavigationControllerRouter? { get }
}

...

class VCFactory: ViewControllerFactory, Routable {

  weak var router: NavigationControllerRouter?
....
}

После этого вы сможете передать ссылку на создание

  private lazy var router: NavigationControllerRouter = {
    let viewControllerFactory = VCFactory()
    let router = NavigationControllerRouter(navController, factory: viewControllerFactory)

    viewControllerFactory.router = router

    return router
  }()
...