Повторное использование View Controller в шаблоне Coordinator - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть поток (Flow A) ViewController в моем приложении для iOS. Поток A довольно сложный (в зависимости от обстоятельств некоторые контроллеры представления отображаются раньше или не отображаются вообще и т. Д.). Чтобы справиться с этим, я использую шаблон координатора.

код (упрощенный):

protocol Coordinator {
    func start()
}

protocol FlowACoordinatable {
    var coordinator: FlowACoordinator
}

class FlowACoordinator: Coordinator {

    private var navigationController: UINavigationController

    private var firstVC: FirstViewController
    private var secondVC: SecondViewController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() { ... }

    func present(_ viewController: (FlowACoordinatable & UIViewController)) {
        viewController.coordinator = self
        self.navigationController.pushViewController(viewController, animated: true)
    }

    ...
}

class FirstViewController: UIViewController, FlowACoordinatable {

    var coordinator: FlowACoordinator?

    func buttonTapped() {
        self.coordinator?.goToNextStep()
    }
}

....

FlowACoordinator содержит логику о том, как и когда представлять контроллеры представления с помощью метода present(). Пока все хорошо.

Теперь у меня есть второй поток, Flow B, в основном отличающийся от потока А. За исключением того, что я хочу разделить контроллер представления между ними, давайте назовем его SharedViewController. Здесь все становится странным, потому что я не очень хорошо представляю, как разделить этот контроллер представления между ними.

Проблема: у меня двусторонняя связь: координатор устанавливает себя в качестве координатора контроллера представления, который он представляет, а контроллер представления вызывает методы для координатора в ответ на взаимодействие с пользователем. SharedViewController управляется одним из двух Координаторов, и каким-то образом он должен передавать информацию текущему Координатору, независимо от того, какой из них.

Пока я нашел два решения, оба из которых не удовлетворяют:

  1. Дополнительный координатор, который обрабатывает только SharedViewController - это много накладных расходов и в значительной степени наносит ущерб цели Координаторов.

  2. Реализация FlowACoordinatable, FlowBCoordinatable, ... в SharedViewController, с несколькими свойствами координатора и вызовом всех из них в соответствующее время. Также много накладных расходов, шаблонный код и звонки координаторам.

Есть идеи, как решить эту проблему?

1 Ответ

0 голосов
/ 12 июля 2019

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

Это нормально, когда данному viewController сам координатор не нужен. Например, давайте назовем это DisplayPopupViewController. Я создаю протокол под названием CanDisplayPopupProtocol:

protocol CanDisplayPopupProtocol {}

extension CanDisplayPopupProtocol where Self: Coordinator {
    func toDisplayPopupViewController() {
        let vc = DisplayPopupViewController.instantiate()
        navigationController.pushViewController(vc, animated: true)
    }
}

Тогда в Coordidnator1:

extension Coordinator1: CanDisplayPopupProtocol{}

А в Coordinator2:

extension Coordinator2: CanDisplayPopupProtocol{}

Теперь оба координатора имеют метод toDisplayPopupViewController ().

Как я уже говорил, это нормально, когда мне не нужно передавать координатор viewController, в этом случае DisplayPopupViewController не нуждается в координаторе, поскольку он будет отклонен и не будет нуждаться в навигации.

Но это становится намного сложнее, когда в этом случае необходимо назначить координатор viewController, какой координатор я передаю?

Решение, которое я нашел, которое не очень элегантно с моей точки зрения, состоит в том, чтобы изменить тип координатора в viewController на протокол Coordinator, поэтому вместо этого:

weak var coordinator: Coordinator1?

Я буду использовать:

weak var coordinator: Coordinator?

А затем в CanDisplayPopupProtocol я проверю, с каким координатором я имею дело, и назначу правильный координатор viewController, например:

protocol CanDisplayPopupProtocol {}

extension CanDisplayPopupProtocol where Self: Coordinator {
    func toDisplayPopupViewController() {
        let vc = DisplayPopupViewController().instantiate()
        switch self {
        case is Coordinator1:
            vc.coordinator = self as? Coordinator1
        case is Coordinator2:
            vc.coordinator = self as? Coordinator2
        default: break
        }
        navigationController.pushViewController(vc, animated: true)
    }
}

Это не красиво, и есть еще один недостаток. Внутри DisplayPopupViewController каждый раз, когда мне нужно использовать один из методов координатора, мне нужно проверить, какой тип координатора я использую.

switch coordinator {
case is Coordinator1:
    (coordinator as! Coordinator1).toDisplayPopupViewController()
case is Coordinator2:
    (coordinator as! Coordinator2).toDisplayPopupViewController()
default: break
}

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

...