XCodeでEXC_BAD_ACCESSを中断しますか?
-
06-07-2019 - |
質問
iPhone開発とXCode全般は初めてで、 EXC_BAD_ACCESS
シグナルのトラブルシューティングを開始する方法がわかりません。エラーの原因となっている正確な行でXCodeを中断するにはどうすればよいですか?
問題の原因となっている行でXCodeを停止させることはできないようですが、デバッグコンソールに次の行が表示されます。
日10月25日15:12:14 jasonsmacbook TestProject [1289]: CGContextSetStrokeColorWithColor: 無効なコンテキスト
日10月25日15:12:14 jasonsmacbook TestProject [1289]: CGContextSetLineWidth:無効なコンテキスト
日10月25日15:12:14 jasonsmacbook TestProject [1289]: CGContextAddPath:無効なコンテキスト
日10月25日15:12:14 jasonsmacbook TestProject [1289]: CGContextDrawPath:無効なコンテキスト
2009-10-25 15:12:14.680 LanderTest [1289:207] ***-[CFArray objectAtIndex:]:メッセージの送信先 割り当て解除されたインスタンス0x3c4e610
今、 UIGraphicsGetCurrentContext()
から取得したコンテキストに描画し、描画したいオブジェクトに渡します。
さらに試行錯誤のデバッグを行ったところ、クラスでプロパティを持っている NSMutableArray
がゾンビであることがわかりました。クラスの init
関数に入りました。使用しているコードは次のとおりです。
if ((self = [super init])) {
NSMutableArray *array = [NSMutableArray array];
self.terrainBlocks = array;
[array release];
}
return self;
}
[array release]
の行を削除し、 EXC_BAD_ACCESS
シグナルが表示されなくなったが、なぜこれが機能するのか混乱している。プロパティを使用すると、自動的に保持されるため、リークしないように init
内からプロパティを解放する必要があると考えました。私はこれがどのように機能するかについて完全に混乱しており、すべてのガイドとStackoverflowの質問を読んだだけで、私のinitメソッド内でプロパティを設定する方法についてさらに混乱しています。どちらの方法が最良であるかについてコンセンサスは得られていないようです。
解決
EXC_BAD_ACCESSエラーの場合、通常、リリースされたオブジェクトにメッセージを送信しようとしています。これらを追跡する BEST の方法は、 NSZombieEnabled を使用することです。
これは、実際にオブジェクトを解放することなく、「ゾンビ」としてラップすることで機能します。そして、通常は解放されるはずであるというフラグをその中に設定します。このようにして、再度アクセスしようとしても、エラーを起こす前の状態を把握しており、この少しの情報で、通常はバックトラックして問題の内容を確認できます。
これは、デバッガーが有用な情報を時々たたくときにバックグラウンドスレッドで特に役立ちます。
非常に重要な注意事項では、これがデバッグコードのみであり、配布コードではないことを100%確認する必要があるということです。何もリリースされないため、アプリはリークし、リークしてリークします。このことを思い出させるために、このログをappdelegateに入れます:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
正確な行を見つけるのにサポートが必要な場合は、ビルドと実行( CMD-R )ではなく、ビルドとデバッグ( CMD-Y )を実行します)。アプリがクラッシュすると、デバッガーは正確にどの行を表示し、NSZombieEnabledと組み合わせて、正確な理由を見つけることができるはずです。
他のヒント
アレイについて。行
NSMutableArray *array = [NSMutableArray array];
は、実際には保持されたオブジェクトではなく、自動解放オブジェクトを提供します。おそらく次の行で保持されますが、3行目でリリースしないでください。 これ
を参照してください。これは基本的なルールです:
“ alloc”で始まる名前のメソッドを使用してオブジェクトを作成すると、オブジェクトの所有権を取得します。または“ new”または“ copy”を含む(たとえば、alloc、newObject、またはmutableCopy)、または保持メッセージを送信する場合。リリースまたは自動リリースを使用して、所有するオブジェクトの所有権を放棄する責任があります。オブジェクトを受け取ったときはいつでも、それをリリースしてはいけません。
Xcode 4では、[スキーム]ドロップダウン(左上、停止ボタンの右隣)をクリックしてゾンビを有効にできます->スキームの編集-> [診断]タブ->ゾンビオブジェクトを有効にする
Xcode / gdbは常に EXC_BAD_ACCESS
で中断します。呼び出しスタックを上に移動して、それをトリガーしたコードを見つける必要があります。
これらの種類のエラーは、多くの場合 autoreleased
オブジェクトで発生することに注意してください。つまり、問題の最終的な原因は EXC_BAD_ACCESS
をトリガーした呼び出しスタックにありません。 NSZombieEnabledとNSAutoreleaseFreedObjectCheckEnabledが役立つのはそのときです。
古いスレッドに対する新しい答え... XCode 4でEXC_BAD_ACCESS例外を診断する最も効果的な方法は、Instrumentsを使用してアプリのプロファイルを作成することです(XCodeから[Product / Profile]をクリックし、[Zombies]を選択します)。これは、割り当て解除されたオブジェクトに送信されたメッセージを識別するのに役立ちます。
Stanford CS193Pクラスから:シンボル objc_exception_throw
にブレークポイントを追加する(手動でブレークポイントを編集することで)場合、何がうまくいかなかったかをよりよく把握できます-物事を先に進めますデバッガが自動的に停止する場所では、物事がわかりにくくなり、スタックトレースが台無しになりがちです。 objc_exception_throwで停止すると、多くの場合、問題の原因となったアクセス/操作を正確に振り返ることができます。
別の有用なアプローチは、例外が発生した直後にトリガーするブレークポイントを設定することです:
ブレークポイントウィンドウを開き(–ブレークポイントを表示–ブレークポイント)、“ objc_exception_throw”という2つのシンボリックブレークポイントを追加します。および“ [NSException raise]"
差出人: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/
同じエラーが異なるミスの解決策を探して、ウェブから来ている他の人のために追加したかっただけです。私の場合、「@」を追加するのを忘れたキー名にタイプミスがあるNSDictionaryをインスタンス化しようとしたときに同じエラーが発生しました。私の鍵の前に:
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
同一の回答を見逃していないことを望みますが、プロジェクトの依存関係またはフレームワークと互換性がない可能性がある古いiOSバージョンのシミュレーターで実行しているため、一部のプロジェクトでこのエラーがスローされる可能性があることがわかりました。 iPhone 4Sのような、より古いシミュレーターのバージョンで起こっていることに気づく前に、私はこれらの1つを追い続けていました。アプリはサポートを試みることすら想定されていませんでした。
より詳細なエラーメッセージが表示されていれば良かったのですが、それが発生したフレームワークの責任だと思います...とにかく、これはかなり一般的な検索の着陸であり、おそらくこれは誰かがだましやすくなります自分が見つけたのと同じくらいひどく起きている。
ゾンビを有効にする前に、まず警告がある場合はすべて削除することをお勧めします。 return
のない非void関数のような単純なものがこのエラーを引き起こす可能性があります。警告が表示されない場合は、他の回答が示すように進みます。