segue を使わないで画面遷移と、画面遷移するときに引数を渡す

アプリを作ってて、ある object をタッチしたら画面遷移したいときがあります。

普通に segue を使えばよいと思ったのですが、例えば object が UIImageView で、月〜日と書かれた絵だった場合、月〜日の object それぞれから segue を引っ張る必要が生じ、さすがに将来分かりにくいだろうと。segue を使わず画面遷移し、願わくば、繊維先の画面には引数を渡したいなと思い調べました。

画面遷移の仕組みはすごく簡単で、遷移先の viewController を生成し、その後、

presentViewController

を実行すればよい。問題は、遷移先の画面に引数を渡す方法ですが、ここかなりハマりましたね。結論からすると、viewController を生成するときに、少し工夫が必要で、

+ (instancetype) instantiateViewControllerWithMessage:(NSDictionary *)msg

のような、class method を作っておきます。引数は NSDictionary 型の msg という変数になりますが、これは、お好みに応じてご自由にどうぞ。

遷移先の viewController を生成するとき、次のようにします。

STQuestionsController* vc = [STQuestionsController instantiateViewControllerWithMessage:quizDic];

[self presentViewController:vc animated:YES completion:nil];

先ほど作成した instantiateViewControllerWithMessage を使って生成し、それを presentViewController に渡してやるということです。

ここまでは良かったんですが、いま作っているアプリの特徴として、object をタップしたとき、サーバにアクセスして情報を取り出し、それを遷移先に渡してやる必要がありました。ここでハマったのが、画面遷移したら確かに NSDictionary は渡っているのですが、タイムラグがあるようで、遷移先の画面を表示したときに UILabel にきちんと情報が表示されないという現象が・・・

これも調べたところ、Objective-C は thread safe ではないので、画面遷移するとき、main thread で実行するように指定してやる必要があると。未確認ですが、サーバから情報を取出すのに NSURLSession を使っていますが、NSURLSession を使うと遅延が起こりがちだと・・・

なので、回避するには、次のように実行します。

dispatch_async( dispatch_get_main_queue(), ^{

                  STQuestionsController* vc = [STQuestionsController instantiateViewControllerWithMessage:quizDic];

                  [self presentViewController:vc animated:YES completion:nil];

              });

これでやっと遅延せず、めでたく遷移した画面に情報がきちんと表示されました。

何度も書きますが、分かってしまえば簡単なことなんですが、わかるまでが大変で・・・