読者です 読者をやめる 読者になる 読者になる

夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【Objective-C】リリースビルドでクラッシュ発生!原因はあいつか!

Objective-C cocos2d Xcode

そろそろリリース時期も近くなったので、初めてリリースビルドを試してみました。

実機で走らせてみると全ての敵キャラクターが画面左下に向かって飛んで行きます。そしてしばらくするとクラッシュ。
そして、シミュレーターで実行する場合は正常に動きます。
以前Profileで実行したときにも同じ現象が発生しました。
デバッグビルドとリリースビルドの違いを調べて行くと、どうも最適化の設定が怪しそうです。
デバッグビルドのOptimization LevelはNone [-O0]でリリースビルドの方はFastest, Smallest [-Os]になっています。これをデバッグビルドを同じNoneに設定すると正常に動作するようになりました。

ここで以前ブログに何か書いた事を思い出しました。
この記事この記事です。

そうです、__weak指定のインスタンス変数にコンビニエンスコンストラクタで生成したオブジェクトを入れると最適化を掛けることにより速攻解放されてしまうようなのです。
なので、addChildで失敗します。
リリースビルドではその時点ではクラッシュしませんが、デバッグビルドで最適化フラグを変更するとaddChildでnilを入れたというエラーメッセージを出してクラッシュします。
これを解決するには、一旦ローカル変数で生成したオブジェクトを受けてaddChildします。
ローカル変数に入れたオブジェクトはその変数のスコープ内では解放されませんので、それを__weakのインスタンス変数に入れてあげればOKです。

具体的には、

__weak CCSprite* _test;
というインスタンス変数にオブジェクトを入れたい場合、

こうではなく
_test = [[CCSprite spriteWithFile:@"test-sprite.png"];
[self addChild:_test];

こうします。
CCSprite* temp = [[CCSprite spriteWithFile:@"test-sprite.png"];
[self addChild:temp]
_test = temp;

いきなりリリースビルドにするとデバッグのしようがないのでデバッグビルドで最適化オプションを変えて試してみる事をお勧めします。
少なくとも今回のバグの場合はエラーメッセージを見れば場所は特定できました。