Coordinator Part1


Coordinator Pattern


Coordinator Patternは、ビューコントローラ間の論理ストリームを整理するための構造設計Patternです.
簡単に言えば、これは、ビュー間のスクリーン切替コーディネータを一度に管理することを意味する.
5つの素子からなる.
  • コーディネータプロトコル:View Present,定義Dismissメソッド
  • コーディネータインスタンス:コーディネータプロトコルのインスタンスを使用して、ビューコントローラの作成方法を知っています.
  • ルータプロトコル:View Present,定義Dismissメソッド
  • ルータインスタンス:ルータプロトコルを使用するインスタンス、コーディネータとの違いを定義し、どこで表示するか、どのように表示するかではありません.
  • ビューコントローラインスタンス:ビューコントローラ同士の間で、どこでどのように表示されるか分かりません.

  • コーディネータパターンクラス図srouce:raywenderlich
    使用目的は以下の通りです.
  • ビューコントローラ間の依存関係
  • ビューコントローラの再可用性を向上させるには、「
  • 」を選択します.
  • 運転時にビューコントローラシーケンスを決定する場合、
  • Router


    RouterはCoordinator PatternでビューのPresentメソッドとDismissメソッドをどのように定義しますか.
    import UIKit
    
    public protocol Router: AnyObject {
      func present(_ viewController: UIViewController, animated: Bool)
      func present(_ viewController: UIViewController, animated: Bool, onDismissed: (() -> Void)?)
      func dismiss(animated: Bool)
    }
    
    extension Router {
      public func present(_ viewController: UIViewController, animated: Bool) {
        present(viewController, animated: animated, onDismissed: nil)
      }
    }
    プロトコルは,表現反発法を定義した.

    NavigationRouter


    UInavigationControllerの使用時にRouterを作成する方法
    import UIKit
    
    public class NavigationRouter: NSObject {
      private let navigationController: UINavigationController
      private let routerRootController: UIViewController?
      private var onDismissForViewController: [UIViewController: (()->Void)] = [:]
      
      public init(navigationController: UINavigationController) {
        self.navigationController = navigationController
        self.routerRootController = navigationController.viewControllers.first
        super.init()
        self.navigationController.delegate = self
      }
    }
    NavigationRouterは、UINavigationControllerおよびRootViewController、ならびにビューが失われたときの動作を記憶するためのDictionaryである.
    を選択します.
    現在、[UIViewController: (() -> Void)?)]はルータプロトコルを採用しています.
    extension NavigationRouter: Router {
      public func present(_ viewController: UIViewController, animated: Bool, onDismissed: (() -> Void)?) {
        onDismissForViewController[viewController] = onDismissed
        navigationController.pushViewController(viewController, animated: animated)
      }
      
      public func dismiss(animated: Bool) {
        guard let routerRootController = routerRootController else {
          navigationController.popToRootViewController(animated: animated)
          return
        }
        performOnDismissed(for: routerRootController)
        navigationController.popToViewController(routerRootController, animated: animated)
      }
      
      private func performOnDismissed(for viewController: UIViewController) {
        guard let onDismiss = onDismissForViewController[viewController] else {
          return
        }
        onDismiss()
        onDismissForViewController[viewController] = nil
      }
    }
    NavigationRouterで、表示されたビューコントローラをパラメータとして使用します.送信されたビューコントローラはナビゲーションコントローラにプッシュされ、onDismissForViewControlに登録されます.presentメソッドは、ビューが破棄される時間を定義する.dismiss(animated:)がない場合は、一番下のビューコントローラがポップアップされます.
    ある場合、通常は対応するビューコントローラさえpopし、その前にrouterRootViewControllerを呼び出す.この方法は、ビューを表示するときに定義されたdiskモジュールを実行し、ディックマニュアルでクリーンアップします.

    Coordinator


    コーディネータプロトコルは、各ビューコントローラ間の階層を表すために使用されます.
    コーディネータ契約は次のとおりです.
    public protocol Coordinator: AnyObject {
      var children: [Coordinator] { get set }
      var router: Router { get }
      
      func present(animated: Bool, onDismissed: (()->Void)?)
      func dismiss(animated: Bool)
      
      func presentChild(_ child: Coordinator, animated: Bool)
      func presentChild(_ child: Coordinator, animated: Bool, onDismissed: (()->Void)?)
    }
    Coordinatorプロトコルに準拠するオブジェクトをサブオブジェクトとします.
    ルーターを所有しています.
    extension Coordinator {
      public func dismiss(animated: Bool) {
        router.dismiss(animated: animated)
      }
      
      public func presentChild(_ child: Coordinator, animated: Bool) {
        presentChild(child, animated: animated, onDismissed: nil)
      }
      
      public func presentChild(_ child: Coordinator, animated: Bool, onDismissed: (()->Void)?) {
        children.append(child)
        child.present(animated: animated, onDismissed: {[weak self, weak child] in
          guard let self = self, let child = child else { return }
          self.removeChild(child)
          onDismissed?()
        })
      }
      
      public func removeChild(_ child: Coordinator) {
        guard let index = children.firstIndex(where: { $0 === child }) else { return }
        children.remove(at: index)
      }
    }
    childが表示されると、child View Controlがchildに登録されます.onDismissingモジュールは、実行時に自己クリアするモジュールです.

    Simple Example


    簡単な実例として,Coordinatorモードをさらに検討する.

    単純に3つの異なるビューコントローラがあると仮定します.
    非Coordinatorモードの一般的な方法で階層を表示すると、
    1.ViewController 1でViewController 2をインスタンス化してプッシュします(ナビゲーション基準は現在の場合があります).
    2.ViewController 2でViewController 3をインスタンス化してプッシュします.
    このビューコントローラと各ビューコントローラの内容には、画面切り替えに関するコードがあります.
    //View Controller1
    func buttonAction() {
    	navigationController?.pushViewController(ViewController2, animated: true)
    	//or
    	present(ViewController2, animated: true)
    
    }
    
    //View Controller2
    func buttonAction() {
    	navigationController?.pushViewController(ViewController3, 	animated: true)
    	//or
    	present(ViewController3, animated: true)
    }
    
    
    //View Controller3
    func buttonAction() {
    	navigationController?.popViewController(animated: true)
    	//or
    	dismiss(animated: true))
    }
    
    Coordinatorモードでは、このセクションはビューコントローラから削除され、2つの構成部品、Coordinator、Routerによって別々に作成されます.
    では、ビューコントローラはすでにCoordinatorに割り当てられたボタンを押していますので、画面を移動してください!ハンドルやデリードアを教えるだけでいいです.Routerで切り替える方法(push,present):
    「View Control 1->View Control 2」はCoordinatorによって管理されます.

    Concrete CoordinatorがViewControllerの階層を知っていて、ビューコントローラがDelegateやHandlerなどに切り替えるように要求されている場合は、Routerで切り替える方法を決定します.

    長所


    Coordinator Patternの利点は、Coordinatorから分散したビュー階層を一目で見ることができ、ビュー切り替えに関連するコードがビューコントローラから削除されるため、よりリアルにビューを表示することに集中できることです.
    ただ、小さすぎるシステムでは、かえって追い越しになります.