ObjecTips

Swift & Objective-C で iOS とか macOS とか

Storyboard で UIViewController の dismiss を設定できるようにする

Storyboard で segue を設定して画面遷移を作っていく時、Modal 表示した ViewController にキャンセルボタンを設置する事がままある。
この時の ViewController への実装は

- (IBAction)cancel:(id)sender
{
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

の様になる。
キャンセル操作の場合は完了(done)操作と違って ViewController を閉じる以外は何もしない上に、キャンセルボタンを実装する様々な ViewController の数だけこれと同じ実装を何度も行う事になる。

OS X の NSViewController には

- (void)dismissViewController:(NSViewController *)viewController NS_AVAILABLE_MAC(10_10);

この dismiss メソッドの他にStoryboard上でアクションを接続できる

/* Dismisses the ViewController.  If the presenter is a ViewController, it will be sent a -dismissViewController: message with this ViewController as the parameter.  Does nothing if the receiver is not currently presented.
*/
- (IBAction)dismissController:(id)sender NS_AVAILABLE_MAC(10_10);

というメソッドが用意されている。
コメントによれば presenter が ViewController の場合 dismissViewController: メソッドを自身を引数として呼ぶよう実装されているらしい。
実装の中身はこの様になっていると思われる。

- (IBAction)dismissController:(id)sender
{
    [self.presentingViewController dismissViewController:self];
}

画面を閉じるだけの操作であればStoryboard上でこのアクションを接続するだけで良い。

これに習って iOS の方でもIBActionな dismiss メソッドを実装する。
UIViewController のカテゴリ拡張として実装する事でどの ViewController でも使えるようになり、また IBAction として実装する事でStoryboard上でも利用できる。

かっちり実装するなら、カテゴリ名とメソッド名に prefix を付けてカテゴリ名は UIViewController+XXIBAction メソッド名は - (IBAction)xx_dissmiss:(id)sender; などにすると良い。

結果、以下の様にStoryboard上で dismiss のアクションを設定できるようになる。

f:id:Koze:20150509232323p:plain

図では画面左下の ViewController から Modal で NavigationController を表示し、NavigationController の rootViewController が画面右上の ViewController になっている。
キャンセルボタンに dismiss: を設定し実行すると画面左下の ViewController に戻る。

一つこのカテゴリを実装しておくとStoryboard上で完結できる事が増えて楽になる。