presentViewController で画面遷移し、直前の画面ではなく、いくつか前の画面に戻るには・・・

presentViewController で画面遷移し、直前の画面ではなく、いくつか前の画面に戻るにはどうするか。

今作っているアプリでは、

画面 1 → 画面 2 → 画面 3 と遷移し、

画面 3 で戻るボタンを押したら画面 1 に戻りたい。

直前の画面に戻るには、

dismissViewControllerAnimated

を使えばよいのですが、上記の例では画面 2 を飛ばして画面 1 に戻りたい。

このようなことをするには、次のような方法があった。

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];

え、そんなことしたら、途中の画面はどうなるの?と思ったら、賢いですね、途中の画面もちゃんと消してくれる。

ちなみに、.presentingViewController はもっと続けて書けるので、上記の例で、例えば、画面 4, 5, 6 と遷移した後、画面 1 に戻りたくなったら .presentingViewController をいっぱい書けば大丈夫。もちろんその気力があればですが・・・

なお、presentingViewController ですが、Xcode で present まで入力して tab キーで補完すると presentedViewController になってしまうことがあり、気づかないと error になってしまうので注意が必要なんだと。

 

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];

              });

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

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

 

SpriteKit か、UIViewController か・・・

iOS のアプリを作るとき、ゲームじゃないんだけどちょっとゲームっぽい画面を作らなくちゃいけなくて、さて、SpriteKit を使うべきか、あるいは、普通に UIViewController で済ませてしまうか、悩ましいときがあります。自身の中でも、どう区別すべきか、都度悩んでいたのですが、選択する際のコツがわかりました。

SpriteKit のライフサイクルは 1/60 秒で、1/60 秒ごとに method を呼べます。何かの判定を行いたい、例えば、常に動いている object がありタップしたタイミングで何かのアクションを行いたい、といった場合は、SpriteKit の方がよいでしょう。1/60 秒ごとに判定を入れることができます。

一方、event の主体がユーザのアクション(例えばタップ)によるものならば普通に UiViewController でいいと思います。SpriteKit は、1/60 秒ごとに method を呼べますが、換言すると、それだけ電池を食うので、必要なければ使わなくてよいと。

以前からどっちがいいかなーと思っていたのですが、その場で答えが出なくても、考え続けていると、後になってから急に思いつくことってありますね。なんか久しぶりの感覚。

 

UINavigationController と UITabBarController

UINavigationController と UITabBarController を同時に使う方法は以前解決したつもり。開発を進めていると、ボタンを選択し + ボタンを押しても別のデータが追加されてしまう。ボタンを押したら、初回はいいのですが色々画面を切り替えていると問題が起こるようで、navigationController が 切り替わっていない。

現象を把握するのにすごい時間がかかってしまった。タブバーのボタンを押したら初回は 最前面の view が表示されるタイミングで viewDidLoad が呼ばれる。でも、2回目ボタンを押したら呼ばれない。すでにメモリにロードされているから。これが問題で、各 viewController では、viewDidLoad method では navigationController の初期化を行なっているので、呼んでくれないと、前の navigationController が残ってしまっているので、画面に応じた適切な navigation が表示されないということ。

解消するために、navigationController に対応する m と h を作り、delegate では、self.delegate = self という、謎の delegate を宣言し、delegate method である 

-(void)tabBarController:(UITabBarController*)tabBarController
didSelectViewController:(UIViewController*)viewController

にて、[viewController vieDidLoad]; と、強制的に選択されたら viewDidLoad を呼ぶようにするとうまくいった。

delegate の使い方として自身を指定することから、なんとも珍妙な形なので、あとで修正することにしよう。

結局、テンプレートで navigationController を選択しているので、AppDelegate に tabBarController が書かれておらず、自分で書かないとダメなのだと。

と、原因がわかればすんなりなのですが、わかるまでが大変で、1 週間ぐらい悩んでしまいました。

 

ヴェポライザーでシャグ :Bali Shag blue American blend

ジャンゴを吸ってからオリエントの旨さにはまり、オリエントがブレンドされたシャグ はないのかと調べたら、Bali Shag blue American blend があり買ってみた。

これ、旨い。

酸味がややきつすぎだけど、これが特徴なんでしょうね。コクがありキック感もありオリエントの酸味あり、煙も結構出る。

アクロポリスに近いとの感想をどこかで読んだけど、確かに似ていて、こちらの方が酸味が強いか。あと、煙が軽い。アクロポリスの煙はもっと粘着する。あと、以前吸ったコルツのアップルシナモンにも似てけど、こっちの方がキック感あり。

40g で 970 円とやや高いけど、ハマる。ヴェポライザー に向いている。

Bali Shag は赤を買ったことがあるのですがこちらは添加物がいっぱいの感じでしたが、blue American blend は葉が感想気味で、それほど添加物の感じがしない。

Bali Shag には nature というのがあるが、こちらもオリエントがブレンドされているようなので、次買ってみようかな。

Bali Shag は入手しやすいのもいいね。

 

ヴェポライザーでシャグ :Red Bull Blond

新しいシャグ を探して、買ってみました Red Bull。説明によると、キャラクターはライトだそうで、軽めなのかなと思える表現で、ちょっと買うのをためらってしまいましたが、あまり売っていないシャグ なので、買える時に買っておこうと思い買いました。

結果、悪くないです。キック感そこそこ、甘みそこそこ、酸味もそこそこ、香ばしさもそこそこと、どれも及第点のため、このタバコの特徴は何か問われるとふと悩んでしまいますが、キック感がそれなりにあるのはよかったです。

ちょっと値が張るので毎回買うのは無理ですが、また買ってみようかなと思える味でした。

 

ヴェポライザーでシャグ :RASTA Menthol

以前から買ってみたかった RASTA。Menthol の在庫があったので買ってみました。

感想は、ま、悪くないです。キック感ほどほど、甘みほどほど、酸味少なめなのでタバコっぽいけど、やや物足りない感も。

Colts Menthol と比較すると、Colts の方が甘みがあるし、少しだけキック感が強い。ただ、Colts は 40g もあり、正直、早く次の買いたいと思ってしまうので、25g の RASTA は消費するタイミングがよく、絶妙なグラム数だと思います。

通勤途中のタバコ屋に売っていたら、また買ってもいいかなと言う感じ。