Segue で画面遷移するときにパラメーターを渡してみる
昨日はTableViewを使ったUIを作っていたのですが、おなじみの
テーブルのセルをタップしたら、関連情報が次の画面で表示される
という動作をやってみたかったので色々調べてみました。
大筋
Windows Store Application ならば Frame.Navigate(targetPageClass, parameter)
のように遷移用のメソッドで直接パラメーターを渡す事ができ、パラメーターも Page.onNavigatedTo(navigateEventArgs)
メソッドの引数から受け取る事ができます*1。
引数でパラメーターを受け取ることができるので、どのタイミングでパラメーターが渡って来るのかが非常に分かりやすく、かつスマートです。
しかし、iOSのフレームワークにはそういった機能は無いようです。
遷移先のViewControllerにpublicなメンバを作り、遷移前にそこにデータを突っ込んでパラメーターにします。
delegateパターンほど汚い感じはしませんが、うーん、好きじゃないなぁ…
今回は、タップされたセルの番号を次の画面に渡してみます。
手順
昨日の続きです。StoryBoard上にTableViewControllerを配置してあり、次のViewControllerに遷移するSegueを作成済みと仮定します。
移動先をカスタムした View Controller にする
データを受け取るためには、遷移先のViewControllerにパラメーター受け取り用のメンバを作らなければなりません。
そして、テーブルをタップした後に遷移する先のViewControllerが自作のViewControllerであるとStoryBoardに書く必要があります。
という訳で、カスタムしたViewControllerの作成から行ってみましょう。
プロジェクトに、 ViewController を継承したクラスを追加します。
今回は CutsomViewCOntroller という名前にしました。
パラメーター受け取りのため、 CustomViewController にメンバを追加します。
今回はテーブルのセルの番号を受け取るので、 NSInteger 型の rowNumber というメンバを追加しました。
"CustomViewController.h" を以下のように編集します。
#import <UIKit/UIKit.h> @interface CustomViewController : UIViewController @property NSInteger rowNumber; @end
CustomViewController をStoryBoard上のViewControllerと関連づけます。
"Main.storyboard" を開き、遷移先ViewControllerを選択して、Identity InspectorのCustom Classの欄に "CustomViewController" と入力します。
これでパラメーターを渡す準備はできているのですが、このままではViewは真っ白。
パラメーターが渡ったのかどうかわからないので、Viewをちょっといじります。
ラベルを置いて、そこに選択されたセルの番号を表示してみましょう。
遷移先の CustomViewController の中に適当なLabelを一つ置いて、 "CustomViewController.h" にOutletを作成します。
今回は label
という名前で作成しました。
受け取ったパラメーターをラベルに設定しましょう。
CustomViewController クラスの rowNumber
に受け取ったパラメーターが入っているようにするので、 viewDidLoad
のタイミングでラベルの文字を仕込んでやると良いでしょう*2。
"CustomViewController.m" の viewDidLoad
を以下のように編集します。
- (void)viewDidLoad { [super viewDidLoad]; // @property で生成したメンバへは、_(メンバ名) でアクセスできる _label.text = [NSString stringWithFormat:@"%d", _rowNumber]; }
これで、パラメータが渡っていれば遷移後に行番号が表示されるはず!
パラメーターの受け渡し
それではパラメーターを渡しましょう。
遷移元のViewControllerである TableViewController を編集します。
まず "TableViewController.h" に "CustomViewController.h" をインポートするように指示します。
#import <UIKit/UIKit.h> #import "CustomViewController.h" @interface TableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate> @end
次に "TableViewController.m" の prepareForSegue:sender:
を以下のように編集します。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"selectRow"]) { CustomViewController *vcntl = [segue destinationViewController]; // <- 1 vcntl.rowNumber = [self.tableView indexPathForSelectedRow].row; // <- 2 } }
prepareForSegue:sender:
は performSegueWithIdentifier:sender:
などで Segue が実行されると、実行直前に自動的に呼び出されるようです。
ただし、どんなSegueが実行される時も呼び出されるので、複数のSegueを定義している場合は identifier を調べて、今実行中のSegueがどのSegueなのかを調べる必要があります。
ここでは、実行された Segue が "selectRow" だったらば、遷移先のViewControllerのインスタンスを取得し(1)、遷移先ViewControllerのメンバーにパラメーターを渡しています(2)。
渡しているのは、テーブル上で現在選択されているセルの番号です。
これで必要な作業は終わりました。
シミュレーターで実行してみると、前回同様数字がずらり。
適当に4番なんかをタップしてやると、
ちゃんとラベルに行番号が表示されていますね!
もちろん、タップする行を変えると、次の画面で出てくる数字も変わります。
遷移時のパラメーターと言いつつ、オブジェクトのメンバにデータを代入するだけなんですよね。
複雑なオブジェクトもコピーする事無く、直接受け渡しできるので、省メモリと言えば省メモリなのかも知れません。
もちろんその分だけメモリ管理は大変になる訳ですが。