清洁Swift - 没有segues的路由

时间:2018-01-10 10:25:23

标签: ios swift design-patterns architecture

我发现Clean Swift架构中的Router负责导航并向/ view controllers.传递数据。有些示例和articles描述了Routers使用segues传递并与视图控制器通信。当我不想使用来自Storyboard的任何segue时,便利设计会是什么?是不是可以在Clean Swift中传递没有segue的数据?如果您用最简单的完整示例进行描述,我将不胜感激。

3 个答案:

答案 0 :(得分:5)

文章说你可以:

  

// 2.以编程方式呈现另一个视图控制器

您可以使用它来手动创建,配置和推送viewController。

实施例

让我们假装你有ViewController按钮(手柄推):

final class ViewController: UIViewController {

    private var router: ViewControllerRouterInput!

    override func viewDidLoad() {
        super.viewDidLoad()

        router = ViewControllerRouter(viewController: self)
    }

    @IBAction func pushController(_ sender: UIButton) {
        router.navigateToPushedViewController(value: 1)
    }

}

ViewController具有router实施ViewControllerRouterInput协议。

protocol ViewControllerRouterInput {
    func navigateToPushedViewController(value: Int)
}

final class ViewControllerRouter: ViewControllerRouterInput {

    weak var viewController: ViewController?

    init(viewController: ViewController) {
        self.viewController = viewController
    }

    // MARK: - ViewControllerRouterInput

    func navigateToPushedViewController(value: Int) {
        let pushedViewController = PushedViewController.instantiate()
        pushedViewController.configure(viewModel: PushedViewModel(value: value))
        viewController?.navigationController?.pushViewController(pushedViewController, animated: true)
    }

}

navigateToPushedViewController func可以使用你想要的任何参数(最好在配置新的vc之前封装参数,所以你可能想要这样做。)

并且PushedViewController没有任何具体实施。只需configure()方法和assert(通知您有关configure()次来电的通知):

final class PushedViewModel {

    let value: Int

    init(value: Int) {
        self.value = value
    }

}

final class PushedViewController: UIViewController, StoryboardBased {

    @IBOutlet weak var label: UILabel!

    private var viewModel: PushedViewModel!

    func configure(viewModel: PushedViewModel) {
        self.viewModel = viewModel
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        assert(viewModel != nil, "viewModel is nil. You should call configure method before push vc.")

        label.text = "Pushed View Controller with value: \(viewModel.value)"
    }

}

注意:同样,我使用Reusable pod来减少样板代码。

结果:

enter image description here

答案 1 :(得分:2)

如上所述,根据您的应用设计,您可以使用navigateToSomewhere方法的选项2/3/4。

func navigateToSomewhere()
  {

    // 2. Present another view controller programmatically
    // viewController.presentViewController(someWhereViewController, animated: true, completion: nil)

    // 3. Ask the navigation controller to push another view controller onto the stack
    // viewController.navigationController?.pushViewController(someWhereViewController, animated: true)

    // 4. Present a view controller from a different storyboard
    // let storyboard = UIStoryboard(name: "OtherThanMain", bundle: nil)
    // let someWhereViewController = storyboard.instantiateInitialViewController() as! SomeWhereViewController
    // viewController.navigationController?.pushViewController(someWhereViewController, animated: true)
  }

答案 2 :(得分:1)

您需要跨协议传递数据

protocol SecondModuleInput {
    // pass data func or variable
    var data: Any? { get set }
}

protocol SecondModuleOutput {
    // pass data func or variable
    func send(data: Any)
}

第一位主持人

class FirstPresenter: SecondModuleOutput {

    var view: UIViewController

    var secondModuleInputHandler: SecondModuleInput?

    // MARK: SecondModuleInput
    func send(data: Any) {
        //sended data from SecondPresenter
    }
}

第二位主持人

class SecondPresenter: SecondModuleInput {

    var view: UIViewController

    var secondModuleOutputHandler: SecondModuleOutput?

    static func configureWith(block: @escaping (SecondModuleInput) -> (SecondModuleOutput)) -> UIViewController {
        let secondPresenter = SecondPresenter()
        secondPresenter.secondModuleOutputHandler = block(secondPresenter)
        return secondPresenter.view
    }

    // Sending data to first presenter
    func sendDataToFirstPresenter(data: Any) {
        secondModuleOutputHandler?.send(data: data)
    }

    // MARK: FirstModuleInput
    var data: Any?
}

路由器

class FirstRouter {

    func goToSecondModuleFrom(firstPresenter: FirstPresenter, with data: Any) {

        let secondPresenterView = SecondPresenter.configureWith { (secondPreseter) -> (SecondModuleOutput) in

            firstPresenter.secondModuleInputHandler = secondPreseter
            return firstPresenter
    }

        //Pass data to SecondPresenter
        firstPresenter.secondModuleInputHandler?.data = data

        //Go to another view controller
        //firstPresenter.view.present(secondPresenterView, animated: true, completion: nil)
    //firstPresenter.view.navigationController.pushViewController(secondPresenterView, animated: true)
    }
}