パフォーマンス向上を目指して

新作アプリ「トーキングメモリーズ」をついに発表してしまい、もう逃げるに逃げられない状況へと自ら追い込みました。

そんな状況なのに、結構笑えない事態が発覚しました。
いや・・・今更!?って感じなのですが。

タイピングがメインのアプリなのに、タイピングの処理がかなり重くなってしまい
iPhone4sではまともにプレイできないことが発覚しました(*´Д`)=3
iPhone5ですら相当重い・・・

これはマズイと重い、今日はあらゆる作業を後回しにして1日中メモリ消費量の改善と
パフォーマンス向上のため、ソースコードとにらめっこしていまいました。

 

入力パフォーマンスの向上

iOSの標準キーボードでは予測変換が表示されます。
この機能自体はとても便利ですが、これを消そうと思っても消せません。

IMG_0006

この予測変換バーを極力出さないようにするために、私がとった方法は
UITextFieldを2つ用意して、1文字入力する度にメインとダミーを切り替えてみました。
この方法で比較的表示されなくなったのですが(全くとは言わないw)、1つ最大のデメリットがあり、
コンマ何秒の間に多くの処理が動くため、相当動作が重くなってしまいました。
iPhone4sはもちろんのこと、iPhone5でも重い。
正直言って、こんな動作ではプレイできない。

でも・・・これに気がついたの実は今日なんです。
この画面の開発は半年程前には終わっていましたが、ほとんどiPhone6でデバッグをしていたため
全く気が付かず・・・
iPhone5や4sでは画面のレイアウト調整程度だったり、そこまでガッツリテストをしていなかったのが原因。
iPhone6がいかに高スペックか、よくわかりました。

文字入力制限タイマーやBGM再生などをスレッド処理させてみたり、
今までは気にもしなかったマルチスレッド処理で頑張ってみたものの、結局納得のいかないパフォーマンスレベル。

・・・結局、予測変換バーは表示させることにしました。
きっと凄腕プログラマーなら予測変換を表示させることなく、サクサクなパフォーマンスを実装
できると思いますが、今の自分にはこれが限界です。

リリースまでに暫く時間がありますので、これからも頑張っていきます。

 

メモリ改善にむけて

そもそも、今まではそんなに重いと思ったことはなかったのに。
何が原因だろうと思い、画面を見ていたら随分華やかになっていたこと・・・
そうです、今までは画面のUIパーツが完成していなかったので、
カラフルなUIViewをところどころ配置して何となくの画面を作っていました。
画像が完成したことで大量のUIImageViewでパーツを配置していきます。
当然メモリも増えていくわけです。

a1
a2

画像を配置していく分には何も問題ないのですが、そのやりかたに問題がありました。

UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"hoge"]];
imageView.frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview:imageView];

こんな感じに画像を貼りつけていくわけですが、
imageNamedを使用すると、リソースファイルがキャッシュされ表示は高速ですがメモリを食ってしまいます。
そこで、こんな風に変えてあげます。

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"hoge" ofType:@"png"];
UIImage* img = [[UIImage alloc] initWithContentsOfFile:imagePath];
UIImageView* imageView = [[UIImageView alloc] initWithImage:img];
imageView.frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview: imageView];

このやり方はリソースファイルがキャッシュされないものの、表示はimageNamedと比べると遅くなります。
今から3年前、「ヤンデレ彼女+PLUS」の着せ替え機能も当初はimageNamedで実装をしていましたが、
とある理由でこの方法に切り替え、あまりの表示の遅さに驚いた記憶があります。
それだけimageNamedが早いということだけ、新人iOSアプリ開発者さんは覚えてくれれば幸いです。

さて、これに直して、少しだけ改善されましたが、それでもメモリが食い続けていきます。
画面遷移ごとにメモリがどんどん増え続けていく。
これはメモリを自動的に解放していくARCに移行してから、気にし出した悩みです(^^;

最初は気にしなかったメモリも、何度も画面を遷移し続けると増え続け、次第にメモリ不足となり
タイピングゲームに支障が出てきたり、最終的にクラッシュします。

グーグル先生のお力を拝借して、調べた結果どうやらUIImageViewを初め、ちゃんとメモリ解放されていないことが原因のようでした。

UIImageViewを解放するときはこうしたほうがいいよ!
ということで実装したコードがこちら

imageView.image = nil;
imageView.layer.sublayers = nil;
[imageView removeFromSuperview];

こちらのサイトで詳しく説明されておりますが、どうやら

画像をメモリ上に置くための UIImage の場合は、UIImageView.image と結びつけているためにまずは切り離してやる必要があります。

とのこと。
iOSアプリ、Objective-Cを触って早数年。
まだまだ知らないことがたくさんあります。

あらゆるソースコードを見直して、メモリが食い続ける不具合は随分改善されました。

 

これでも・・・

しかし、これでもiPhone4sではプレイには耐えられないレベルです。
もうハッキリいいます。iPhone4sはダウンロードはできますが対象外です!
iPhone5では比較的プレイできるレベルには向上されました。
申し訳ありません。

 

とまぁ、完成に向けて日々頑張っておりますが、まだ完成まで時間がかかる模様。
トーキングメモリーズは9月リリース予定です。
どうぞご期待ください。

 

ところで・・・
なんで、Objective-Cなの?Swiftじゃないの?
っていうツッコミは要りません。
このプロジェクトを着手した当時はSwift1.0から2.0に移行するかしないかの時期で、
この作品は私の中で最後のObjective-C開発にしようと考えています。

2 件のコメント

  • はじめまして。リンクを貼っていただきありがとうございました。

    メモリって面倒ですよね。特に自動と半自動と手動が入り乱れるシステムでは把握が大変ですし、全自動も開放したいタイミングでしてくれなかったりして、難しいです。

    phpでも unsetを多用するおいらとしてはプリントデバッグでメモリー量の把握をしがちなのですが、iOSやmacOSの場合は、xcode付属の Instruments とにらめっこしながら進めると、すっきりとしたメモリー管理がしやすいと思います。

    ちなみに、おいらは未だにiPhone4Sユーザーです。iOS10からはサポートされないので潮時ですね。おいらが開発する時は、ロースペックに合わせて創るようにしています。ただ、4Sはアスペクト比も違うので、世間的には非サポートのほうが良いのかもしれません。

    • はじめまして。
      コメントありがとうございます!

      ARCに移行したときは「なんて便利なんだ、すごい楽!」と思っていましたが、やっぱりそんなに甘くありませんでしたね(^^;
      ただ今MRCでコーディングしろ、と言われても書ける自信がありません・・・

      おっしゃるとおり、iPhone4sはiOS10のサポートがされませんね。
      iPadが3.5インチになってしまうので、このサイズを切り離せないのが厄介ですが、基本的に4sは非サポートにしていこうと思います。

  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です