co-working space

今日はこどもの日ですが、妻が子供の服を買いに行くというので任せることにして、co-working space でアプリを作ることに。

いつもの如くなかなか出発しない。なんか考え込んでいる様子で、行動するのに時間がかかる。ようやく出発したのが 16 時過ぎ。行きたいところは 9 時から開いているので、朝一から行こうと思っていたのに 7 時間待ち。行ってくれたからまだよかったけど、途中、「行くのやめる?」とか言い出す始末で、おいおい、お前が行くっていってたんだろ、と言いたくもなるわな。

ま、そんなこんなで、co-working space に着いたのが 1640 で、もともと 1 日コースを考えていたのですがとばっちりを喰らい遅くなってしまい、 2h にしました。

中は広い。人が、5・6 人ですかね。休日は少ないのでしょう。これだけ広いと果たしてどこに座ろうかかなり悩んでしまう。fix と書いてあるとこは専用のシートらしいので座ってはならないと。窓際のソファーにしたけれども肘あてがないのでなんか嫌だけど、ま、しょうがないなと。後から見たら、端には仕切りのある個室風のブースもあったので、今度はあそこにしよう。電源確保。正直ソファーはあまり良くないように思いました。肘あてないし、クッションが硬い。初めてなのでこれも経験です。

コーヒー買いたいと思ったら、外の cafe にてセルフで 150 円。安いものです。さて、喫煙所は・・・と思ったら、奥の方にありました。ちなみに、入口は 1 箇所じゃなくて、道中のドアにカードをかざせば入れると。

ちなみに、家族もいないのでわざわざ出かけないで静かな家でやればいいじゃんと思うなかれ、家だと切迫感がないというか、ちょっと寝てからとか、つい、のんびり構えてしまうのです。co-working space だと、「お金を払っているのだから成果を出さないと」という心情が働くのでしょうね、やる気になるのです。ちょっと寝ようかなもできないし。ちなみに今日の目標は 2 つあって、テスト用に zero クリアの機能を実装するのと、ログインの機能がうまく働いていなかったので実装しようと思っていて、どちらも実装できました。やっぱり、お金を払っているから成果をださないと、という心情は偉大なものです。

あそこに来ている人はどんな人なんでしょうね。自分よりも随分長くいる人が多かったです。余計なお世話ですね。空調効いてて快適です。夏とかすごい快適でしょうね。あ、iPhone の電源とコードを忘れてしまった・・・ピンクのケーブルで気に入っていたのだけれどしょうがないです。アキバで違うの買ってこよう。

と、充実した 2h でした。今度有給とって行ってこよ。

 

統制と自治:オブジェクト指向

iOS のアプリを Objective-C で作っています。オブジェクト指向の言語なので、delegate とか、仕組みが提供されているものなので、知っていればればその恩恵を受けられます。今回は、自作した機能でオブジェクト指向の恩恵を受けることができた典型的な事例があったので書き記しておこうと思います。

作ろうとしているのは、月曜日から日曜日のアイコンを表示し、それぞれの曜日をタッチするとクイズが始まる・・・といった機能です。曜日のアイコンは、その曜日にならないとタッチできません。曜日アイコンの演出は、回答できるのにまだ回答していない曜日のアイコンは目立つように少し大きく・小さくを繰り返すアニメーションを実装し、また、すでに回答してしまった曜日には、肩に花をつけようとしました。

こういったことをやろうとすると、まず考えつくのは、曜日アイコンを表示している view に、各曜日のアイコンを規定し、各曜日それぞれの状態を調べ、状態に応じて演出を実装するという方法です。controller を実装するということでしょうか。各日付のオブジェクトを統制しようとする方法です。これ、結構大変で、記述する量がものすごく多くなるのは避けられません。量が多いという事は後から見てよくわからなくなる可能性が高いのと、記述している最中でも、途中でデバッグする際に苦労するでしょう。これしか方法を知らなければ、文句も言わず(いや、言いながらか)書くしかないのです。今、月曜日から日曜日の 7 つのオブジェクトを統制するためのコードを書いていますが、よく言われるのが、1 日から 30 日までに拡張するとどうなるか・・・これ、かなりきついと思います。学校の教室で教師が何人の生徒を見ることができるか、多くなるほど大変ですよね、それと同じ事です。

せっかくオブジェクト指向の言語を使っているのだから、もっと自治的な方法はないか考えてみました。曜日のアイコンを class にしてそこに制御を描くようにするとコードの記述量は減るし、管理するのは基本的に一つのオブジェクトなので、全然楽です。

かなり今更ですが、オブジェクト指向のよい点は何?と問われたとき、すぐに思い浮かぶ典型的な例だったので、備忘のため書いておきました。

トレイルランニング:愛宕山ー吾国山、縦走

6 月のレースに備えて、トレイルの練習をしておこうといつものコースへ。前回は 12 月の末に行ったので、4 ヵ月ぶり。季節も冬だったのに今は春というか近頃は初夏なので服装が結構悩ましいところ。朝 0530 に起きて、岩間駅に 7:30 頃到着。半ズボンに着替え、ウインドブレーカを脱いでいざ登山道へ。今日は、朝から 16 度と暖かかったものの、半ズボンと半袖で電車乗るのもどうかなと着てきたのですが、トレイルではまちがいなく暑いだろうと上着は脱いで。基本的に日陰の中を走るので、服装はちょうどよかったですね。水は 500 ml ペットボトル 2 本。これも、ちょうど良かったです。

愛宕山では、桜祭りとのぼりが出ていましたが、もう散っていて地面に花びらが残っていました。山でも今年は開花が早かったんですね。ツツジがちょうど見頃のように思いました。意外に、ツバメが飛んでて春を実感しました。

このコースはいつも冬にばかり行っているので、人に会うことが無くあっても 1 人か 2 人ということが多く、人気ないのね・・・と勝手に思っていたのですがそんな事はありません。今日は同じ方向で 11 人、反対からの人も同じく 11 人すれ違いました。こんなに多くの人に会うのは初めてだったので、少し驚きです。

それにしても、わかっちゃいるけどアップダウンがきつい。なので距離の割りには足を酷使することになるのでトレーニングに向いているのだろう。普通、縦走というと登ったあとは平らに連なっていて、アップダウンはもちろんあってもそんなにきつくない。ここは思いっきり登って思いっきり下っての繰り返しで平らなところがほとんどない。唯一あるのがはじめの展望台までの道のり。それ以外はアップダウンがきつい。登り・下りの連続。しかも、のぼりが半端なくきつい。のぼりがきついということは下りもきついということで、足へのダメージは半端ない。ピークはだいたい 4 回あると思った方が良い。展望台、大福山、難台山、吾国山だ。いや、地名が分からないけどピークは 6 回と考えた方がよいか。4 回とかじゃなかった。そう言えば難台山で違う道に行きかけてしまった・・・素直に標識のある方に行けばいいのに、その奥の道に行ってしまい、なんかおかしい、いつもと違う気がすると戻ったのが正解。あの道を進んでいたら果たしてどこについていたのか・・・地面がだいぶ乾燥しているのに、横滑りしてしまう始末。これは傾斜がきついから。危険な箇所ははじめの展望台となんとか館すぎた後の登り。あそこはいつも軽くぬかるんでいて滑る。最近雨が降っていないはずなのになぜかぬかるんでいる。そう言えば、吾国山の登りの途中でトカゲ?ヤモリ?がいた。少し太っていたのでサンショウウオ?とも思ったけど、山の中腹にいるなんて不思議。

今回は一番速かったと思います。途中息継ぎしないで行けたのが良かったのか。何回も来ているのでだいぶコースを覚えていますね。吾国山への登りの道中、ここキッツイんだよなぁ、前回は途中で息継ぎしちゃったよなぁと思い、今回は意地でも前に(上に?)進んでやると決意して、息継ぎなしで登り切りました。足がだいぶできている感じで良かった。吾国山頂には 0945 に到着、山を降りて水田に出たのが 1000 でした。でも、やっぱり水戸線には間に合わなくて、1056 まで 30 分ぐらい待つことに。 

その後宍戸駅で降りてはなさかで風呂と食事。連休中なのですごい混んでいるかなと思ったら、そうでもなくて、やっぱりここは穴場っぽくていいなと。前回はカラオケ大会していたけれども今回は何もやってなくて大型テレビでNHK。ちょうどのど自慢がはじまり、あー、なんか和むぅ〜と。

レースへ向けたトレーニングも最終章で、あとはつくばまでのロング走を残すのみか。あれきついのね・・・35Km もあるから。ま、できると思いますが。

 

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 週間ぐらい悩んでしまいました。