1. プレゼンターはビューから情報を照会できます
これに満足して回答するには、特定のケースに関する詳細情報が必要です。コールバック時にビューがより多くのコンテキスト情報を直接提供できないのはなぜですか?
プレゼンターにCommandオブジェクトを渡すことをお勧めします。これにより、プレゼンターはどのような場合に何をすべきかを知る必要がなくなります。プレゼンターは、オブジェクトのメソッドを実行し、必要に応じて、ビューの状態について何も知らなくても (したがって、高い結合を導入することなく) 独自の情報を渡すことができます。
- ビューはxと呼ばれる状態にあります ( yおよびzとは対照的です)。とにかく、それは自分の状態を知っています。
- ユーザーがアクションを終了します。View は、デリゲート (Presenter) に終了を通知します。非常に関与しているため、通常の情報をすべて保持するためにデータ転送オブジェクトを構築します。この DTO の属性の 1 つが
id<FollowUpCommand> followUpCommand
. View は ( and とは反対に) を作成し、XFollowUpCommand
それに応じてそのパラメーターを設定してから、それを DTO に入れます。YFollowUpCommand
ZFollowUpCommand
- プレゼンターがメソッド呼び出しを受け取ります。具体的なものに関係なく、データに対して何かを行います
FollowUpCommand
。次に、プロトコルの唯一のメソッドである を実行しますfollowUpCommand.followUp
。具体的な実装は何をすべきかを知っています。
一部のプロパティで switch-case/if-else を実行する必要がある場合、ほとんどの場合、共通プロトコルから継承するオブジェクトとしてオプションをモデル化し、状態の代わりにオブジェクトを渡すと役立ちます。
2.モーダルモジュール
提示モジュールまたは提示モジュールがモーダルかどうかを決定する必要がありますか? -- 提示されたモジュール (2 番目のモジュール) は、モーダルでのみ使用するように設計されている限り、決定する必要があります。物についての知識を物自体に入れる。表示モードがコンテキストに依存する場合、モジュール自体は決定できません。
2 番目のモジュールのワイヤーフレームは、次のようなメッセージを受け取ります。
[secondWireframe presentYourStuffIn:self.viewController]
パラメータは、プレゼンテーションが行われるオブジェクトです。asModal
モジュールが両方の方法で使用されるように設計されている場合は、パラメーターも渡すことができます。それを行う方法が 1 つしかない場合は、この情報を影響を受けるモジュール (提示されたもの) 自体に入れます。
次に、次のようなことを行います。
- (void)presentYourStuffIn:(UIViewController)viewController {
// set up module2ViewController
[self.presenter configureUserInterfaceForPresentation:module2ViewController];
// Assuming the modal transition is set up in your Storyboard
[viewController presentViewController:module2ViewController animated:YES completion:nil];
self.presentingViewController = viewController;
}
ストーリーボード セグエを使用する場合は、少し異なる操作を行う必要があります。
3. ナビゲーション階層
また、2 番目のモジュールのビューがナビゲーション コントローラーにプッシュされたとします。「戻る」アクションはどのように処理する必要がありますか?
「すべてVIPER」に行く場合、はい、ビューからそのワイヤーフレームに移動し、別のワイヤーフレームにルーティングする必要があります。
提示されたモジュール ("Second") から提示されたモジュール ("First") にデータを戻すには、 に追加SecondDelegate
して実装しFirstPresenter
ます。提示されたモジュールがポップする前に、メッセージを送信しSecondDelegate
て結果を通知します。
ただし、「フレームワークと戦わないでください」。VIPER の純粋さを犠牲にすることで、ナビゲーション コントローラーの優れた点を活用できるかもしれません。セグエは、すでにルーティング メカニズムの方向への一歩です。カスタム アニメーションを導入するワイヤーフレームのメソッドについては、 VTDAddWireframeを参照してください。UIViewControllerTransitioningDelegate
たぶんこれが役に立ちます:
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return [[VTDAddDismissalTransition alloc] init];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[VTDAddPresentationTransition alloc] init];
}
最初に考えたのは、ナビゲーション スタックと同様にワイヤーフレームのスタックを保持する必要があり、すべての「アクティブな」モジュールのワイヤーフレームは互いにリンクされているということです。しかし、そうではありません。ワイヤーフレームはモジュールのコンテンツを管理しますが、ナビゲーション スタックは、どのビュー コントローラーが表示されるかを表す唯一のスタックです。
4. メッセージの流れ
異なるモジュールは、ワイヤーフレームのみを介して会話する必要がありますか、それともプレゼンター間のデリゲートを介して会話する必要がありますか?
別のモジュール B のオブジェクトにプレゼンター A からのメッセージを直接送信すると、どうなるでしょうか?
レシーバーのビューが表示されないため、たとえばアニメーションを開始できません。プレゼンターはワイヤーフレーム/ルーターを待つ必要があります。そのため、再びアクティブになるまでアニメーションをキューに入れる必要があります。これにより、Presenter がよりステートフルになり、操作が難しくなります。
アーキテクチャに関しては、モジュールが果たす役割について考えてください。クリーン アーキテクチャがいくつかの概念を掘り起こすポート/アダプタ アーキテクチャでは、問題はより明白です。類推として、コンピューターには多くのポートがあります。USB ポートが LAN ポートと通信できません。情報の流れはすべて、コアを経由する必要があります。
アプリの核となるのは何ですか?
ドメインモデルはありますか? さまざまなモジュールから照会される一連のサービスはありますか? VIPER モジュールは、ビューの中心にあります。モジュールが共有するものは、データ アクセス メカニズムと同様に、特定のモジュールに属していません。それが核心と呼べるものです。そこで、データ変更を実行する必要があります。別のモジュールが表示されると、変更されたデータが取り込まれます。
ただし、単なるアニメーションの目的で、ルーターに何をすべきかを知らせ、モジュールの変更に応じてプレゼンターにコマンドを発行します。
VIPER Todo サンプル コード:
- 「リスト」はルート ビューです。
- リストビューの上に「追加」ビューが表示されます。
- ListPresenter は AddModuleDelegate を実装します。「追加」モジュールが終了すると、ListPresenter はそのワイヤフレームではなく、ビューが既にナビゲーション スタックにあることを認識します。
5.状態保持
現在選択されているピン、MapViewController、MapPresenter、または MapWireframe の状態を保持する必要があるのは誰ですか?戻ったときにどのピンの色が変わるかを知るためには?
なし。ビュー モジュール サービスでステートフルを回避して、コードの保守コストを削減します。代わりに、変更中にピンの変更の表現を渡すことができるかどうかを調べてみてください。
エンティティが状態を取得できるように (Presenter や Interactor などを介して) 手を伸ばしてみてください。
Pin
これは、ビュー レイヤーでオブジェクトを作成し、それをビュー コントローラーからビュー コントローラーに渡し、そのプロパティを変更してから、変更を反映するために送り返すという意味ではありません。NSDictionary
シリアル化された変更を行うにはどうすればよいですか? そこに新しい色を入れて、PinEditViewController
背面からプレゼンターに送信すると、MapViewController
.
今私はだまされました:MapViewController
状態が必要です。すべてのピンを認識する必要があります。次に、変更辞書を渡すことを提案したので、MapViewController
何をすべきかがわかります。
しかし、影響を受けるピンをどのように特定しますか?
すべてのピンに独自の ID がある場合があります。おそらく、この ID はマップ上の位置にすぎません。多分それはピン配列のインデックスです。いずれにせよ、何らかの識別子が必要です。または、操作中にピン自体を保持する識別可能なラッパー オブジェクトを作成します。(ただし、色を変更する目的にはばかげているように聞こえます。)
状態を変更するためのイベントの送信
VIPER は非常にサービスベースです。メッセージを渡し、データを変換するために結び付けられた、ほとんどステートレスなオブジェクトがたくさんあります。Brigade Engineering による投稿では、データ中心のアプローチも示されています。
エンティティはかなり薄い層にあります。私が念頭に置いているスペクトルの反対には、ドメイン モデルがあります。このパターンは、すべてのアプリに必要なわけではありません。ただし、同様の方法でアプリのコアをモデル化すると、いくつかの質問に答えるのに役立つ場合があります。
誰もが「データ マネージャー」を通じてアクセスできるデータ コンテナーとしてのエンティティとは対照的に、ドメインはそのエンティティを保護します。ドメインも積極的に変更を通知します。(まずNSNotificationCenter
、 を使用します。コマンドのようなダイレクト メッセージ呼び出しを使用する場合は、それほどではありません。)
これもあなたのピンケースに適しているかもしれません:
- PinEditViewController はピンの色を変更します。これは、UI コンポーネントの変更です。
- UI コンポーネントの変更は、基になるモデルの変更に対応しています。VIPER モジュール スタックを介して変更を実行します。(色を保持しますか?そうでない場合、
Pin
エンティティは常に短命ですが、値だけでなくアイデンティティが重要であるため、エンティティのままです。)
- 対応する の
Pin
色が変わり、 を通じて通知が発行されNSNotificationCenter
ます。
- たまたま (つまり、
Pin
わからない)、一部の Interactor はこれらの通知をサブスクライブし、そのビューの外観を変更します。
これはあなたのケースでもうまくいくかもしれませんが、編集を結ぶと思います