iOSアプリケーションのルーティングレイヤー

ストーリーボードを開いて、 ポジティブな感情があなたが見たものからあなたを圧倒し始めることはあなたに起こりましたか?



現時点では、大規模なプロジェクトの画面間で適切に設計されたナビゲーション(以降、 ルーティング )が非常に重要なタスクになると考えているかもしれません。その解決策は、プロジェクトに参加するすべての人の時間と神経を節約するのに役立ちます



この出版物のルーティングとはどういう意味ですか?



一般的に、これはある画面から別の画面へのパスとして説明できます。 そして、それぞれに独自の方法があります。 誰かがすぐにStoryboard Segueを紹介しますが、誰かがこの挑戦を好きになるでしょう:



self.navigationController?.pushViewController(UIViewController(), animated: true)
      
      





どの時点でルーティングレイヤーを再考する必要が生じる可能性がありますか?





ルーティングレイヤーの再考はどこから始められますか?



何がルーティングに入るかを決定することは重要です。 これらは、 pushViewControllerpopViewControllerpopToViewControllerpopToRootViewControllerpresentdismisssetViewControllersなどのさまざまな遷移を実行するUIViewControllerUINavigationControllerなどの関数です。 また、 ルーティングでは、 アラートアクションシートトーストスナックバーなどのさまざまなポップアップを表示できます。



同様に重要なステップは、トランジションの呼び出し方法を決定することです。 理想的には、移行コードは非常に簡潔で、初めて見た人でも理解できるものです。



 func someFunction() { ... routing(with: .dismiss) }
      
      





遷移のためのUIViewControllerの準備



上記の例を実装しようとすると、 ルーティングUIViewController自体が実装する関数になります。



 extension UIViewController { func routing(with routing: Routing) { ... } }
      
      





次に、パラメーターとして関数に分類されるルーティング要素を作成する必要があります。 迅速に、列挙は非常に柔軟であることが判明し、この状況では最適です:



 enum Routing { case dismiss case preparedNavigation case selectedCityTransport(CityTransport) case selectedTrafficRoute(TrafficRoute) ... }
      
      





同じルーティングパラメーターを異なるUIViewControllerから呼び出すことができ、たとえば、そのような呼び出し中に異なる呼び出しが発生することに注意してください。 したがって、アプリケーション遷移がどの特定のUIViewControllerから呼び出されたかを知る必要があります。 UIViewControllerとトランジションの適切なマッピングをさまざまな方法で実現できます。 ただし、理想的には、 UIViewControllerにこれらの目的のための特定のパラメーターを持たせたいと思います。 たとえば、 禁止されたマジック ランタイムを使用する場合:



 extension UIViewController { enum ViewType { case undefined case navigation case transport ... } private struct Keys { static var key = "\(#file)+\(#line)" } var type: ViewType { get { return objc_getAssociatedObject(self, &Keys.key) as? ViewType ?? .undefined } set { objc_setAssociatedObject(self, &Keys.key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
      
      





UIViewControllerに新しいパラメーターを導入することにより、アプリケーション画面間のすべての遷移呼び出しを収集し、呼び出し元のUIViewControllerの型で分類されるルーティング関数を詳細化できます。



 extension UIViewController { func routing(with routing: Routing) { switch type { case .navigation: preparedNavigation(with: routing) case .transport: selectedCityTransport(with: routing) default: break } } }
      
      





たとえば、各遷移の特定の実装は、個別のプライベートUIViewController拡張に移動できます。



 private extension UIViewController { func preparedNavigation(with routing: Routing) { switch routing { case .preparedNavigation: guard let view = self as? UINavigationController else { break } view.setViewControllers([TransportView()], animated: true) default: break } } func selectedCityTransport(with routing: Routing) { switch routing { case .selectedCityTransport(let object): navigationController?.pushViewController(RoutesView(object), animated: true) default: break } } }
      
      





最終的に何を達成しましたか?





このアプローチは、出版物の著者によって使用されましたか?



最初から迅速に記述された2つのプロジェクトでは、 ルーティングレイヤーの提示された実装を実装することができました。 プロジェクトの1つはRxSwiftを使用して作成され、 ルーティングコールは次のようにラップされました。



 extension Reactive where Base: UIViewController { var observerRouting: AnyObserver<Routing> { let binding = UIBindingObserver(UIElement: base) { (view: UIViewController, routing: Routing) in view.routing(with: routing) } return binding.asObserver() } }
      
      





プロジェクトサイズは55kおよび125k locでした。 ルーティングレイヤー全体を含む各プロジェクトのファイルサイズはほぼ同じで、約600行のコードになりました。



All Articles