2018年2月5日月曜日

東方VGS(iOS)コードレビュー② ViewController

大規模なアプリの場合、ViewControllerが幾つもあったりしますが、東方VGSのViewControllerはひとつだけです。
https://github.com/suzukiplan/tohovgs-ios/blob/master/Touhou%20VGS/VGSViewController.m

更に言うと、その唯一のViewControllerが管理するViewも最大5つ(iPhone4s以前 or iPadの場合は4つ)だけしか無いので、ViewControllerの実装は物凄くシンプルになっています。
※上図では省略していますが、全てのViewの親(ルートView)としてVGSScreenViewというものがあります。

ViewControllerが生成されるとiOSからデリゲートメソッドのviewDidLoadがコールバックされますが、VGSViewControllerでは、そこで上述のViewを作って並べつつ、VGS特有の初期化処理を行っています。

以下、VGSViewControllerのviewDidLoadに実装されている処理内容を見ていきます。

(1) 多重初期化の抑止
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L38-L40
これは、iOS8の時にviewDidLoadが2回実行され結果的にアプリが起動時にクラッシュするバグ(※iOS側のバグ)が発生したので、その時に入れた対処コードです。

このバグ自体、発生条件がかなり限定的なのですが、東方VGS(というか私が作った全てのiOSアプリ)は不運にもその条件に該当してしまったので、当時公開していた全てのアプリにこの対処コードを入れてアップデートしました。(物凄く大変でした)

そういえば、この対処バージョンの東方VGSをアップデートするついでに、東方幻想郷から「Bad Apple!!」を追加しましたが、これは当然そういう意図で追加されたものです。

iOS版東方VGSをAppStoreで公開していた約4年間ほどの短いようで長い歴史の中で、ほぼ唯一不評のレビューが付き、総平均レビュー値を4.9から4.8に下げる原因となったのがコレでした。ただ、普通のアプリだったら「起動すると落ちる☆1」と低評価レビューの嵐となる所、「起動すると落ちる☆5」という風に、不満を言いつつも評価を下げないでくれる人が結構居ることに少し驚きました。
このiOS8デグレード事件以外に、もう一つ不評を買ったのが、AppStoreだとアップデート時の更新内容の説明文を最大4000字書けたので、「4000字きっかり埋める説明文を書いてみよう」と思い立ち、少し長めのポエムを書いた時ですね。 
逆に一番評価が高かったのが「神々が恋した幻想郷」と「芥川龍之介の河童」を追加した時のレビューで、平均☆5.0(約300件ついたレビューがオール☆5)でした。オール耳コピで作る必要がある風神録の楽曲全曲収録という無謀な挑戦ができたのは、この時のオール☆5が原動力になりました。
(2) バージョン切り分け
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L44-L67
この辺のバージョン切り分けは色々と謎ですね。
過去バージョンとの互換性を保つ為に色々な試行錯誤が行われていたようです。(他人事)
iOSの場合、Androidと違ってOSバージョンがフラグメント化しないので、古いバージョンはガンガン切ってしまって良いかと思うのですが、東方VGSではApple側から「おい、やめろ!」と言われるまで最低サポートバージョンをiOS4.3(東方VGSの機能を実現する上で最小限の機能セットが実装されているiOSの最低バージョン)以降にしてました。(最終的には、古すぎるバージョンのiOSをサポートしているとAppleから審査提出を拒否されるようになったので、最低サポートバージョンをiOS6.1にまで引き上げました)

(3) ルートViewの作成
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L68
ViewControllerのルートViewとしてVGSScreenViewというものを作成して追加しています。VGSScreenViewには「タッチイベントを取得してVGSへ送信する」という役割があります。(その役割が無ければルートViewは単なるUIViewでも良かったとも言えます)
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSScreenView.m
普通のiOSアプリを作った事がある人なら、「タッチイベントの処理は各Viewが担えば良いのでは?」と考えるかもしれません。実際にタッチを受け付けるのはVGSViewなので、わざわざタッチイベントを処理する専用のViewなんて設けるのはナンセンスだと言えます。ただし、UIViewは存在自体が結構重いモノなので、Viewをグルーピングする用途しか持たない空のUIViewをルートに配置するのではなく、そこにタッチイベント処理を集約させる機能を持たせ、VGSViewの責務範囲を減らしつつロジック分散するのは、ある意味(※VGSというスペシフィックなモノに限れば)合理的かもしれません。
ちなみに、このViewのグルーピングという考え方でAndroidとiOSで決定的な違いがあります。Androidの場合、Viewのグルーピングを行う専用の機能(ViewGroup)をViewとは分離して定義した一方、iOSの場合Viewのグルーピング機能をそのままView(UIView)に持たせています。結果的に、Viewグルーピングの実装はAndroidの方がシンプルになった反面融通が効きにくいものになり、iOSの方はかなり融通が効く反面実装コストが高く付くものになりました。何れにせよ一長一短あるのですが、だいたいどのアプリも似たり寄ったりなmaterial designとかいうクソみたいなデザインを採用している現状を勘案すると、この部分のスキームは結果的にAndroidの方が優れたものだったのではないかと思っています。
(4) romdata.binの読み込み
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L69-L77
VGSの場合、グラフィック、音声(効果音、BGM)、テキストなどのアセットデータは独自形式のバイナリデータとして「romdata.bin」というファイルに集約しています。そのromdata.binファイルを読み込みメモリ上に配置する処理をここで行っています。そして、ここで読み込んだメモリ上のデータ(ROMデータ)は、アプリのプロセスが生存中維持し続けます。これにより、東方VGSでは一般的なiOSネイティブアプリやUnity等で書かれたゲームアプリを作る時に悩まされる「ガーベージコレクト」が一切発生しません。(その代わりに表現力が貧弱になる)

(5) VGSViewとUIImageViewの作成+配置
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L79-L114
VGSViewというVGSのコア機能を持つViewと、上下の画像イメージの作成と配置をココで行っています。
16:9の端末と4:3の端末で処理が分かれていますね。
iOSアプリを作ったことがある方なら、「これだとiPhone6や6 plusで画面下にスキマが出来てしまうのでは?」と疑問に思うかもしれませんが、東方VGSはiPhone6(4.7")やiPhone 6 plus(5.5")の場合は互換モードで動くので、特に問題なく配置されます。(iPhone Xでどうなるかは知らない)
この部分はちょっと直したいですね...

(6) VGSBarViewの作成+配置
https://github.com/suzukiplan/tohovgs-ios/blob/71464aae09f107fbf02e9ce1989d9bfb80381e37/Touhou%20VGS/VGSViewController.m#L116-L118
最後にVGSBarViewという画面最上部の時計を表示しているViewを作成して配置しています。リリース当初の東方VGSにはこのViewは無くて、iOS標準のステータスバーを表示していました。しかし、iOS側の度重なる仕様変更で嫌気が差し、最終的にはiOS標準のステータスバーを削除して自前のステータスバーを置く形に落ち着きました。
iOSはバージョンアップの都度、かなりラジカルに仕様変更をしてきますが、最も煽りを食うのがこのiOS標準のステータスバーの部分です。ステータスバーはiOS側の持ち物なので、当然といえば当然ですが。(最近では、iPhone Xのあの変態的な形状のステータスバー...ハードレベルで変えてくるから堪ったものではない)

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...