Coordinator Part1
25288 ワード
Coordinator Pattern
Coordinator Patternは、ビューコントローラ間の論理ストリームを整理するための構造設計Patternです.
簡単に言えば、これは、ビュー間のスクリーン切替コーディネータを一度に管理することを意味する.
5つの素子からなる.
コーディネータパターンクラス図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から分散したビュー階層を一目で見ることができ、ビュー切り替えに関連するコードがビューコントローラから削除されるため、よりリアルにビューを表示することに集中できることです.
ただ、小さすぎるシステムでは、かえって追い越しになります.
Reference
この問題について(Coordinator Part1), 我々は、より多くの情報をここで見つけました
https://velog.io/@hey_hen/Design-Pattern-Coordinator
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
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)
}
}
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
}
}
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
}
}
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)?)
}
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)
}
}
簡単な実例として,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から分散したビュー階層を一目で見ることができ、ビュー切り替えに関連するコードがビューコントローラから削除されるため、よりリアルにビューを表示することに集中できることです.
ただ、小さすぎるシステムでは、かえって追い越しになります.
Reference
この問題について(Coordinator Part1), 我々は、より多くの情報をここで見つけました
https://velog.io/@hey_hen/Design-Pattern-Coordinator
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(Coordinator Part1), 我々は、より多くの情報をここで見つけました https://velog.io/@hey_hen/Design-Pattern-Coordinatorテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol