iPachiで起きていた不具合なのですが、
特定の画面を表示中にメモリ不足に陥り
didReceiveMemoryWarningを受け取ると
アプリがクラッシュするという問題をついに
解消しました。
didReceiveMemoryWarning後にクラッシュするので
メモリ管理でどこかがおかしくなっているのだろうとは
予想がつくのですが、いかんせん貧弱なエラーメッセージの
ため、まったく発生元がつかめませんでした。

EXC_BAD_ACCESSとか言われてもさっぱりわからんです。
が、すばらしい記事をみつけました。
NSDebugEnabled
これでクラッシュをおこしているオブジェクトの生成場所を
特定できるので、格段にデバッグ効率があがります。
というわけで、エミュレータでのメモリ不足時のシミュレートと
デバッグのための設定をまとめます。
エミュレータでのメモリ警告のシミュレート
これは簡単です。
iPhone Simulatorをアクティブにして、
メニュー→ハードウェア→メモリ警告をシミュレート
とするだけです。
これで、エミュレータはメモリ不足時の動作をとります。
つまりはAppDelegateでapplicationDidReceiveMemoryWarningが呼ばれ,
各コントローラでもdidReceiveMemoryWarningが呼ばれます。
デバッグの設定
デバッグコンソールに今よりはましなメッセージを出すことと、
クラッシュをおこしたオブジェクトを特定するコマンドを使える
ようにする設定をします。
まずはXcodeメニューで
メニュー→プロジェクト→アクティブな実行ファイルを編集
開いた画面の引数タブ→環境変数に以下の3つを追加
NSZombieEnabled = YES
MallocStackLogging = YES
NSDebugEnabled = YES
設定は以上。
デバッグしてみる
設定後に冒頭と同様のエラーをおこした時のコンソールは
こんな感じに表示されます。
EXEC_BAD_ACCESSだった部分に
-[CALayer retainCount]: message sent to deallocated instance 0x54d140
なんていうメッセージが表示されます。
なるほど。
既にdeallocされてしまったCALayerオブジェクトにretainCountメッセージを送ってしまってくラッシュしていたのか、という所までわかります。
ただ、CALayerはすべてのUIViewにあるし、どのUIViewのことだかはまだわからんと。
ここでデバッグコンソールに以下のコマンドを打ち込みます。
shell malloc_history {PID} {アドレス}
PIDにはアプリのプロセスIDを、アドレスにはクラッシュしたインスタンスのアドレスを入力します。
このコマンドを打ち込んでENTERを押すと
ベロベロっとクラッシュしたインスタンスの生成場所が
表示されます。
この出力結果を下からたどっていくと、おそらく自分がコードを書いたメソッドにたどり着くはずです。
ここでは[RootViewController createToolBar]に見覚えがありました。
その中の+[UIButton buttonWithType:]メソッドを呼んでいる部分のよう。
該当部分のコードはこちら
// infoボタン UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight]; [infoButton addTarget:self action:@selector(flipInfo:) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem *info = [[UIBarButtonItem alloc] initWithCustomView:infoButton]; [infoButton release]; |
コードはinfoマークのボタンを生成して、ツールバーにセットしている部分。
infoButtonを生成しているのは+[UIButton buttonWithType:]で
autoreleaseされるインスタンスを返す初期化メソッドなのに
[infoButton release]として、その場で解放してしまっていました。
そういうことかと。
ここでreleaseして既にdeallocされていたインスタンスに
retainCountメッセージが送られてしまっていたという。
ひとまず[infoButton release]を削除して
エラーが起きないことを確認。
このデバッグ方法は強力でした。
まだまだjavaやC#に比べると原因をたどりづらいですが、
前よりはずいぶんましになりました。








4月 26th, 2009 at 11:58 AM
わかりやすい説明がされていたので、リンクを貼らせてもらいました。問題があれば削除しますので、メールに連絡してください。
4月 27th, 2009 at 1:38 AM
>bitlink Inc.さん
リンク全く問題ありませんよ。
また遊びにいらしてください。
5月 22nd, 2010 at 6:29 AM
当方、Xcode 3.2.2で試してみましたが、
YESの代わりに1を設定することで動作しました。
6月 10th, 2010 at 12:26 AM
デバッグが格段に楽になって、たすかりました。
ありがとうございます。
7月 1st, 2010 at 9:26 PM
Seasonsさん情報ありがとうございます!また遊びにきてくださいー
7月 1st, 2010 at 9:35 PM
>shin-goさん
お役に立てて幸いです。
9月 7th, 2010 at 2:11 PM
[...] ◆参考URL 【iphone】メモリ不足時のシミュレートとデバッグ iPhone開発 didReceiveMemoryWarningとviewDidUnloadの順番 10 iPhone Memory Management Tips [...]
5月 13th, 2011 at 11:58 PM
[...] [...]
5月 25th, 2011 at 2:08 PM
非常に悩んでいた問題を解決出来ました!
本当に感謝します!
6月 27th, 2011 at 4:32 PM
途方にくれていたところ、この方法でなんとか進めそうです!
ありがとうございます。