iOSアプリで画面遷移(モーダルなビューでデリゲート)
Google先生に「iOS 画面遷移」という場合、期待している答えにはたどり着けない。
それは多分、「モーダルでビューを開く」ということになる。一覧から明細をタップしたら切り替わるのは、「Master-Detail」とかいわゆるUINavigation系の話で、別の話。別の話なのだよ!!。ここでは「モーダル」なやつについてメモっておく。
モーダルでビューを開く想定例アプリ
- とある画面Aにボタンがある
- ボタンをタップしたら別の画面Bが「ぴょ」とでてくる
- 画面Bには「閉じる」的なボタンがある
- 画面Bの「閉じる」を押したら、画面Bがひっこんで画面Aに戻る
これだけのことがやりたいのだが…!!
大原則
- UIViewControllerのpresentModalViewController で開く
- UIViewControllerのdismissModalViewControllerAnimated で閉じる
だがしかし
- 画面Bを開くときは、UIViewControllerのpresentModalViewControllerを使う
- 画面Bを閉じるときは、画面BでdismissModalViewControllerAnimatedはしない
だそうだ。
ここにdelegateという考え方がでてくる。そんな回りくどいことしたかねえよというかもしれないが、もし画面Bで入力した値を画面Aで使いたいとしたら、(保存しちゃうという手もあるけど)デリゲートを使ったほうがよいのあるらしい。
あらすじ
- 画面Bのヘッダーファイルに、画面Bデリゲートをつくりメソッドを定義する。プロパティに自分のデリゲートを追加する。
- 画面Aは画面Bデリゲートのメソッドを実装する。そこで画面Bを閉じる記述をする。
- 画面Bを開くときは、UIViewControllerのpresentModalViewControllerを使うが、そのときに、画面Bのデリゲートに画面Aはselfを設定する。
- 画面Bを閉じたい箇所で、画面Bは自身のデリゲートのメソッドを実行する。すると結果的に、画面Aのメソッドが実行されるので画面Bは閉じられる。
「実装」「設定」「メソッド」とか言葉があっているのかわからない。
よく忘れるのは、「画面Bのデリゲートに画面Aはselfを設定する」ところ。これを忘れていると、スカスカなにもおこらない。
画面BをInfoViewControllerとしまして、InfoViewController.hの中身
#import <UIKit/UIKit.h> @class InfoViewController;//プロトコルにわかってもらうために要るらしい // デリゲート @protocol InfoViewControllerDelegate <NSObject> -(void)infoViewController:(InfoViewController*)infoViewController okButtonTapped:(id)sender; @end // 本体 @interface InfoViewController : UIViewController //デリゲート用 retainじゃなくてassign //@property(nonatomic,retain)id<InfoViewControllerDelegate> delegate; @property(nonatomic,assign)id<InfoViewControllerDelegate> delegate; // 画面Bの見た目上の閉じるボタン用 -(IBAction)okButtonTapped:(id)sender; @end
InfoViewController.m(一部)
@synthesize delegate; //これもよく忘れる。この解放についてはまじよくわかんないぉ。ARC前ならnilとかいれちまって終わっているのか?な? ARCだとうんにゃらかんにゃら。 -(void)okButtonTapped:(id)sender{ NSLog(@"InfoViewControllerokButtonTapped..."); // [self dismissModalViewControllerAnimated:YES]; //ここでこれを書くと閉じるけどやらない // デリゲートのメソッドを実行する [self.delegate infoViewController:self okButtonTapped:sender]; }
画面AにあたるViewController.h
#import <UIKit/UIKit.h> // デリゲートのためにこれがいる #import "InfoViewController.h" @interface ViewController : UIViewController<InfoViewControllerDelegate> -(IBAction)showInfo:(id)sender; @end
ViewController.m(一部)
// 画面Bを開く -(void)showInfo:(id)sender{ InfoViewController*infoViewController = [[InfoViewController alloc] initWithNibName:@"InfoViewController" bundle:nil]; // ここを忘れるとスカスカ infoViewController.delegate = self; // 画面Bを開く(開くっていうのか? 違うんだろうなあ) [self presentModalViewController:infoViewController animated:YES]; } // デリゲートのメソッド -(void)infoViewController:(InfoViewController *)infoViewController okButtonTapped:(id)sender{ // ここで閉じられる // このselfは感覚的には画面Aではなく画面B。なぜかというとデリゲートだから [self dismissModalViewControllerAnimated:YES]; }
なんだかもやもや。
単純に閉じるのなから、親から閉じるもあるっぽいし。。。