EXC_BAD_ACCESS例外は、既にリリースされているオブジェクトにメッセージを送信しようとすると発生します。 エラーが発生するまでに、コールスタックに役立つ情報が含まれていないため、状況は通常複雑です。 つまり、どの特定のオブジェクトがリリースされたかは明確ではありません。 さらに、コードがどこでリリースされたかは明らかではありません:)。 アプリケーションがマルチスレッドである場合、さらに楽しくなります。
幸いなことに、 Appleのスタッフは私たちを助けるために最善を尽くしました。 彼らはスタブクラスNSZombieを作成しました。 サポートを有効にした場合(これを行う方法を説明します)、その場所(つまり、メモリ内のアドレス)で各オブジェクトを削除した後、ゾンビは生きてメッセージを受信します。これにより、デバッグ中のオブジェクトを判別できます。リリースしてエラーを修正します。
それでは始めましょう。 ある日、iPhoneまたはMacアプリケーションがクラッシュし始め、デバッガーコンソールに次のメッセージが表示されます。
プログラム受信信号:「EXC_BAD_ACCESS」。
そして、実際には、これ以上何もありません。 おそらく、コールスタックも役に立ちませんでした。
[ グループとファイル]ウィンドウ( xCodeの左側)で、[ 実行可能 ファイル]ブランチを見つけます。 アプリケーションの実行可能ファイルを右クリックし、ドロップダウンメニューから[ 情報を見る]を選択します。 表示されるウィンドウで、「 引数」タブを開き、 NSZombieEnabledおよびMallocStackLoggingNoCompactの 2つの環境変数を追加します。 NSZombieEnabledをYESに設定し、 MallocStackLoggingNoCompactを1に設定します。 どのように見えるかはスクリーンショットに示されています:
ここで、アプリケーションを実行し、エラーを再現するために必要な手順を繰り返します。 デバッガコンソールで、 EXC_BAD_ACCESSを報告する代わりに、次のようなものが表示されるはずです。
2010-01-25 14:35:24.840 MyApplication[1393:20b] *** -[CFString retain]: message sent to deallocated instance 0x42a5060
これは、アドレス0x42a5060にクラスCFStringのオブジェクトがあったことを意味します。 彼はすでに釈放されており、あなたのプログラムは満足しておらず、メッセージretainを彼に送ろうとしています。 このオブジェクトを見つけ、コード内で追加のリリースが呼び出された場所を見つけることは残っています。 どちらのリテインも呼び出されず、特定の状況に依存します:)
以下が役立ちます。デバッガーコンソールで、次のコマンドを入力します。
shell malloc_history 1393 0x42a5060
1393の代わりに、プロセスID(PID)を入力する必要があります。 アプリケーション名の直後のコンソールエラーメッセージで確認できます。 0x42a5060の代わりに、解放されたオブジェクトのアドレスを入力します(エラーメッセージでも確認できます)。
その結果、あなたの目は次のような恐ろしい絵を見ます:
心配しないで、すべてが一見したように怖いものではありません。 近いうちに、コードに存在するクラスとメソッドの名前を探します。 つまり、あなたによって書かれました。 どこかで悪意のあるリリースコールを隠しました。 検索して修正します。
PS私の目の前で、Instruments / ObjectAllocを使用してそのようなエラーをキャッチできることをどこかで読みました。 誰かが私にウォッカをくれたらとても感謝しています...ああ、ヒント