iOSアプリを170倍高速化できた2つの意外な盲点


facebook_ad_all_03

こんにちは、デジタルガジェット大好きなkubotaです。

先日、QAアプリであるアンサーのAndroid版をリリースいたしましたが、iPhone版も着々とバージョンアップしております。
iPhone版アンサーの現在(2014年6月11日時点)の最新バージョンは3.6.0になるのですが、このバージョンで質問詳細画面を内部的に大幅に改修いたしまして高速化しましたので、今回は高速化について書きます。

高速化のポイントは2つです。

  • セルの高さをキャッシュするようにした
  • 日付文字列(YYYY-MM-DD HH:II:SS)ではなく、unixtimeからDateTimeオブジェクトを作るようにした

高速化のきっかけ

高速化を行おうとしたきっかけなのですが、おかげさまで徐々にユーザも増えてきて1つの質問で1000個も回答されるような質問も出てくるようになりました。
また、有名な方に質問してもらおうというイベントも行っており、その時にほんの20分程度で1000回答を超えるような質問が発生してiPhone5やiPhone4sで信じられないくらい動作が重たいといった現象が発生したのをきっかけにこれはまずい!となり、高速化しようとなりました。
ちなみにイベント情報はこちらのアンサー公式ブログ(http://blog.answer.jp/)Twitterにて発信しております。

高速化前のベンチマーク結果

とりあえずベンチマークを取得して問題がある部分を切り出すところから始まりました。
まずは描画部分が重たいのではないかと考えましたが、UITableの特性上あまりデータが多くても描画にそんなに時間はかからないとふんでいたのですが、実際の数値を取得するとどうやらUITableViewの高さを計算する部分でiPhone4で約4秒もかかっていました。
この間は画面が固まってしまってスクロールできなくなっていました。
この現象に関しては初期の読み込み時にはUITableViewは表示していないので、最初は少し時間はかかるかもしれないが高さをキャッシュすることにしようという結論が出ました。
しかしながらiPhone4では1000回答以上あるような質問ではロードに2分以上はかかっている感じがしたので、ここだけではないと調査を続けました。
他で重たそうなのはJSONからオブジェクトに変換している部分くらいしかないと実行時間を測ったところiPhone4で130秒程度かかっていました。
ここだ!ということでオブジェクトに変換している内部を調査したところ『2014-06-11 01:00:00』といった文字列形式の日時をNSDateに変換しているところで時間がかかっていたようなので、サーバ側でUnix時間で返してもらうとなんと1秒を切るようになりました。

高速化前のオブジェクト生成と描画スレッドのベンチマーク結果です。
2行程度の長さの文字だけの1000回答がある質問で、手元にあったiPhone4・iPhone5、iPhone5sでそれぞれを5回ずつ計測した小数点以下2桁の秒数になります。

iPhone4
オブジェクトの生成(秒) 描画(秒)
1回目 130.78 3.90
2回目 130.48 3.63
3回目 132.05 3.77
4回目 132.87 3.79
5回目 133.55 3.85
平均 132.346 3.792
iPhone5
オブジェクトの生成(秒) 描画(秒)
1回目 42.00 1.03
2回目 42.67 1.02
3回目 42.02 1.03
4回目 42.92 1.03
5回目 40.94 1.03
平均 42.118 1.028
iPhone5s
オブジェクトの生成(秒) 描画(秒)
1回目 6.89 0.51
2回目 7.03 0.49
3回目 7.02 0.49
4回目 5.04 0.47
5回目 6.41 0.45
平均 6.478 0.482

高速化後のベンチマーク

なるべく早く改修したバージョンを出したいということでこれだけでもかなりの高速化になったので申請に出すことにしましたが、実際の工数はアプリ・サーバ合わせても1日も使わずに高速化を行えました。
ベンチマークの結果は以下になります。

iPhone4
オブジェクトの生成(秒) 描画(秒)
1回目 0.77 4.04
2回目 0.81 4.10
3回目 0.81 4.10
4回目 0.86 4.08
5回目 0.86 4.24
平均 0.822 4.112
iPhone5
オブジェクトの生成(秒) 描画(秒)
1回目 0.24 1.04
2回目 0.24 1.04
3回目 0.25 1.04
4回目 0.26 1.03
5回目 0.25 1.10
平均 0.248 1.05
iPhone5s
オブジェクトの生成(秒) 描画(秒)
1回目 0.14 0.63
2回目 0.12 0.45
3回目 0.12 0.47
4回目 0.12 0.47
5回目 0.12 0.48
平均 0.124 0.5

また、描画に関しては初めて描画した際にキャッシュを行い2回目、以降回答が削除されている場合など高さが変更される場合を除きキャッシュを使うようにしています。
キャッシュを使用した際の描画のベンチマークは以下になります。

端末名 1回目 2回目 3回目 4回目 5回目 平均
iPhone4 0.54 0.55 0.52 0.53 0.53 0.534
iPhone5 0.15 0.16 0.16 0.16 0.16 0.158
iPhone5s 0.08 0.07 0.07 0.07 0.06 0.07

オブジェクト生成では、iPhone4で160倍以上、iPhone5では170倍近く高速化に成功しました。
iPhone5のほうが倍率では大きいのですが、iPhone4では約130秒以上から0.8秒くらいまで縮まったことで体感的には全然違います。
描画に関しましても2回目以降は全体的に7倍以上早くなることに成功しました。

反省点

今回の高速化を行ったときに思った反省点になります。

実機の検証はなるべく古い端末で行う

開発中、検証は基本的にiPhone5sを使用して行っていたためそれほど遅いと感じていなかったのですが、やはり検証は古い端末で行ったほうがよかったです。

思い込みでの設計

企画の時点でスマートフォンアプリらしく即回答がもらえ、ベストアンサーをつけてその質問は終わりといったイメージがありましたので、多くても100回答くらいと思っていていました。
こういうことから回答を表示するUITableViewの高さキャッシュやオブジェクト生成時のベンチマークなどを行わなかったのですが、これが間違いでユーザがどのような行動を行っても問題なく動く設計を行うべきでした。

大量のデータでテストを行うべきだった

上記とも繋がるのですが、やはり大量の回答がついたような質問でテストをいていなかったのはかなりの反省点です。
これを行っておけば今回のようなことはもっと早く気づくことができたと思えます。

まとめ

いかがでしたか、今回の高速化は工数自体はあまりかかっていないのですがかなり意義のある高速化になりました。
早いことは正義だと思っておりますので、アンサーはこれからも出来るかぎり高速化できそうな部分があれば高速化を行っていきたいと思います。
もちろん安定していないのは駄目なのでしっかり検証しながら行っていきたいです。

アンサーは下記からダウンロードできますので是非とも使ってない方は使ってみてください。
iPhone版アンサー
Android版アンサー

nanapiではエンジニアを募集中です!

最後に、nanapiでは一緒に働いてくれるエンジニアを募集しています。
Webもアプリも好きって方、一緒に働いてみませんか?

株式会社nanapi(ナナピ) | 募集要項 WEBアプリケーションエンジニア