web-dev-qa-db-ja.com

モーダルセグエでUIStoryboardに表示されたモーダルを閉じる方法は?

セットアップ:2つのシンプルなビューコントローラーAとBを備えたストーリーボードをセットアップしました。Aには、モーダルセグエを使用してBに移行するボタンがあります。 BはAの上にモーダルトランジションが表示されます。問題ありません。

質問:簡単なストーリーボードマジックでBをポップしてAに戻る方法はありますか?

これがすべてナビゲーションコントローラーにあり、私がプッシュセグエを使用した場合、ナビゲーションコントローラーによって暗黙的に処理されます。 「戻る」ボタンがあります。モーダルに匹敵するものは何もありません。自分でUIを作成する必要がありますが、BからAに戻るための信号を送るために使用できるセグエメカニズムがあるかどうか疑問に思っています。

これで、BからAに戻ってビルドするoldskoolメソッドは次のようになります。

  • bにデリゲートプロパティを作成する
  • モーダルトランジションセグエが再生されるときにAをBのデリゲートに設定します(AのコードでprepareForSegue:sender:を使用してこれにフックできます)
  • 解任の時期になると、Bは代理人に合図します
  • AはBを閉じるデリゲートメソッドを実装します

これは機能しますが、オーバーヘッドが多すぎて馬鹿げているように感じます。

基本的に「リバースモーダルセグエ」を実行するUIStoryboardメカニックはありませんか?

32
Jaanus

少なくとも少しのコードを書かずにモーダルビューコントローラーを閉じるためのストーリーボードの魔法はありません。

ただし、独自のコードを実装する必要はありますが、必ずしもそれほど多くの問題を抱える必要はありません。ビューコントローラーBに[self dismissViewControllerAnimated:YES completion:nil]を呼び出すボタンを置くだけです。 (ドキュメントは、提示するビューコントローラを閉じるべきであると述べていますが、メッセージは、提示される側で呼び出された場合、メッセージは提示するビューコントローラに転送されることも述べています。あるモーダルビューコントローラーが別のモーダルビューコントローラーから提示される場合など、場合によっては存在する必要があります。self.presentingViewControllerでプレゼンターを明示的に参照し、そこからdismiss...を呼び出すことができます。)

一部のアプリではデリゲートビジネスが表示されます。これは、ビューコントローラーBでユーザーが行ったことをビューコントローラーAに通知する1つの方法ですが、それが唯一の方法ではないためです。 KVO、通知、またはself.presentingViewControllerで参照した後のAのメソッドの単純な呼び出しがあります(BがAから常に提示されていることをBが知っていると仮定します)。そして、AがBで何が起こったかを知る必要がない場合(たとえば、ユーザーが[キャンセル]ボタンを押したため)、それを行う必要はありません。モーダルを閉じて、それで終了できます。


IOS 6以降では、セグエの巻き戻しに別のオプションが追加され、モーダルビューコントローラーを閉じる(または一連のセグエの「バックアウト」)ための「ストーリーボードマジック」が少し提供されます。しかし、このアプローチにはまだいくつかのコードが必要です-ストーリーボードで完全に設定することはできません。ただし、プラスの面では、そのコードは、表示されていないビューコントローラー(B)から情報を取得したビュー(B)に情報を取得するためのパスを提供します。

Appleには アンワインドセグエに関するテクニカルノート があり、詳細に説明していますが、短いバージョンを次に示します。

  1. 巻き戻したいビューコントローラークラスにIBActionメソッドを定義しますto-モーダルビューコントローラーを表すもので、モーダルビューコントローラー自体(質問のビューコントローラーA)。通常のIBActionメソッドとは異なり、これらはUIStoryboardSegue *タイプのパラメーターを取る必要があります。例えば.

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
    
  2. 表示されたビューコントローラー(質問のB)で、コントロールを緑色の終了アイコンに配線し、定義したメソッドを選択します。

  3. Unwindメソッドの実装では、セグエのsourceViewControllerを参照して、閉じられているビューコントローラーから情報を取得できます。セグエは、終了するビューコントローラの非表示を処理するため、dismissViewControllerAnimated:completion:を呼び出す必要はありません。

44
rickster

これを実現するためのisストーリーボードの魔法があります。巻き戻しセグとして知られています。 Aの.hファイルでは、必要な「ターゲットアクション」スタイルのメソッドを実装しますが、必要な多くのアンワインドセグエがあります。モーダルの場合、通常は2つです(キャンセルして保存)。だから私のA.hファイルに追加します:

// A.h file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue;
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue;

ストーリーボードで、AからBへのセグエがある場合、「ターゲットアクション」スタイルのコントロールをBのキャンセル/保存ボタンからBコントローラーの下部にある緑色の「終了」アイコンにドラッグできるようになりました。ストーリーボードで。これを行うと、Xcodeは作成した2つのメソッドを取得します(それらはAのヘッダーファイルにあり、正しい署名(例:IBActionおよびUIStoryboardSegue *。)があり、BはAからのセグエの宛先であるため)。したがって、そこにあります。あなたが探していた絵コンテの魔法があります!

2つのコールバックの実装では、次のようなものがあります。

// A.m file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

最後に、このアプローチがあなたのニーズを満たしているなら、素晴らしいです。完了です。ただし、 "on cancel"または "on save"の場合、プロトコルデリゲート/ dataSource設計パターン全体を結び付けて、ビュー階層からBを削除するためにAに制御を渡す前にBのプライベートプロパティでいくつかの操作を実行したい。

30
John Erck