iOS用のアプリケーションを設計する従来の方法は、MVC(model-view-controller)テンプレートを使用することです。 アプリケーションアーキテクチャにMVCを使用すると、各クラスがモデル、ビュー、またはコントローラーであるという考えが得られます。 アプリケーションロジックの多くはモデルまたはビューの一部ではないため、通常はコントローラーで終了します。 これにより、 Massive View Controllersとして知られる問題が発生します。この問題では、コントローラーの処理が過剰になります。 すべてのロジックがView Controllerに埋め込まれている場合、UIを介してロジックをテストすることになりますが、これはロジックを設計する間違った方法です。 同じメソッドでビジネスロジックとUIコードを組み合わせることも簡単です。 新しい機能を追加したり、バグを修正したりする必要がある場合、どこで変更を加えるかを決定すると同時に、他の場所で予測できない結果が発生することを確認するのは困難です。

VIPER
iOSアプリケーションを設計するためのより良い方法を探して、 ボブおじさんが説明したように、私はClean Architectureに出会いました。 Clean Architectureは、アプリケーションの論理構造をさまざまなレベルの責任に分割します。 これにより、依存関係(データベースなど)を簡単に分離し、レベル間の境界で相互作用をテストできます。
VIPERは、iOSアプリケーション向けのClean Architectureの実装です。
VIPERという言葉は、View、Interactor、Presenter、Entity、およびRoutingの頭字語です。
VIPER構造
要するに、あなたが持っている:
- スクリプトによって提供されるビジネスロジックを含むインタラクター。
- Presenter。表示用のコンテンツを準備するためのロジック(Interactorから取得)およびユーザー入力に応答する(Interactorから新しいデータを要求する)ロジックが含まれています。
- ビュー。Presenterが報告した内容を表示し、ユーザー入力をPresenterに返します。
当初、同僚はこのアーキテクチャをVIPアーキテクチャと呼んでいました。 ある意味、これは「非常に重要なアーキテクチャ」と解釈できるため、権利の侵害です。 他のアーキテクチャソリューションは重要ではないと人々に思わせたくないので、私はそれをVIPERと呼び、後でEとRの意味を思いつきました。
この分離は、 単一責任の原則にも従います。 Interactorはビジネスインテリジェンスを担当し、Presenterは表示を担当し、Viewは視覚的プレゼンテーションを担当します。
以下は、さまざまなコンポーネントとそれらの関係の図です。

インタラクター/インタラクター
Interactorは、アプリケーション内の単純なユーザーケースです。 特定のタスクを実行するオブジェクト(エンティティ)を管理するためのビジネスロジックが含まれています。 タスクは、UIに関係なく、Interactorで実行されます。 同じInteractorは、iOSアプリケーションまたはMac OSのコンソールアプリケーションで使用できます。
Interactorは、主にロジックを含むPONSO(通常のNSObject)であるため、TDD(テストによる開発)を使用して簡単に開発できます。
エンティティ
エンティティは、Interactorが管理するオブジェクトです。 エンティティはインターアクターのみを管理します。 エンティティをプレゼンテーションレベル(つまり、プレゼンター)に転送することはありません。
データストア
データストア(Webサービス、データベースなど)は、エンティティをInteractorに提供する責任があります。 Interactorがビジネスロジックを適用すると、データストアからエンティティをフェッチし、エンティティを管理して、更新されたエンティティをデータストアに返します。 データウェアハウスは、エンティティの永続性を制御します。 エンティティはデータウェアハウスを知らないため、永続化する方法を知りません。
TDD(テストによる開発)を使用してInteractorを開発する場合、ダブル/モックテストを使用して実稼働データウェアハウスを無効にすることができます。 リモートサーバー(Webサービスの場合)またはディスク(データベースの場合)にアクセスすることなく、テストを反復可能で高速にすることができます。
プレゼンター/プレゼンター
プレゼンターは、基本的にUIを制御するロジックで構成されるPONSOです。 ユーザーの対話から入力を収集するため、Interactorに要求を送信できます。 また、PresenterはInteractorの結果を受け取り、結果をビューに表示するのに最も効果的な状態に変換します。
エンティティがInteractorからPresenterに渡されることはありません。 代わりに、動作のない単純なデータ構造がInteractorからPresenterに渡されます。 これにより、Presenterでの「実際の作業」が防止されます。 Presenterは、ビューに表示するデータのみを準備できます。
表示する
ビューは受動的です。 Presenterが表示用のコンテンツを配信するのを待ちます。 彼女はプレゼンターにデータを要求しません。 プレゼンテーション用に定義されたメソッド(たとえば、ログイン画面のLoginView)は、Presenterがこのコンテンツの表示方法ではなく、コンテンツの観点で表現されたより高い抽象化レベルで通信できるようにする必要があります。 プレゼンターは、UILabel、UIButtonなどの存在を認識していません。 プレゼンターは、サポートするコンテンツと、いつ表示するかについてのみ知っています。 プレゼンターは、コンテンツの表示方法を決定する必要があります。
Viewは、プロトコルを使用してObjective-Cで定義された抽象的なインターフェイスです。 UIViewControllerまたはそのサブクラスの1つは、Viewプロトコルを実装します。 たとえば、これはログイン画面です。
@protocol LoginView <NSObject> - (void)setUserName:(NSString*)userName; - (void)setPassword:(NSString*)password; - (void)setLoginEnabled:(BOOL)enabled; @end @interface LoginViewController : UIViewController <LoginView> … @end
ワイヤーフレーム/ワイヤーフレーム
ルーティングは、インタラクションデザイナーによって作成されたワイヤーフレームで定義されているように、ある画面から別の画面へのナビゲーションを処理します。 ワイヤフレームオブジェクトはルーティングを担当します。 ワイヤフレームオブジェクトは、UIWindow、UINavigationControllerなどを所有しています。 彼は、Interactor、Presenter、およびView / ViewControllerの作成と、ViewControllerの構成を担当しています。 Presenterにはユーザー入力に応答するロジックが含まれているため、Presenterはいつ別の画面に切り替えるかを知っています。 ワイヤフレームはこれを行う方法を知っています。 そのため、PresenterはWireframaユーザーです。
例
Interactor、Presenter、Viewの使用方法を示すシンプルなアプリであるCounterアプリを見つけることができます。 次の記事では、このアプリケーションの開発方法について詳しく説明します。 追加の記事では、データウェアハウジングとワイヤフレームの使用について説明します。
フィードバック
したがって、VIPERは、1つのクラスの大量のコードをいくつかの小さなクラスに分割することにより、問題の分離に関してより正確になるように支援します。 各クラスで単一の責任を維持することにより、TDDを使用したクラス開発が簡素化されます。これにより、要件の変化に迅速に対応し、より良いソフトウェアを作成できます。