これは私の最初の投稿です。間違いをお詫び申し上げます。
修正できるクラッシュがありますが、そもそもクラッシュする理由がわかりません。コードを本質的なものに減らしてクラッシュさせようとしました。
GCFTile *currentTile;
NSInteger repeatCount = 0;
do {
currentTile = self.remainingTilesArray[0];
if (repeatCount == 0) {
[self.remainingTilesArray removeObjectAtIndex:0];
[self.remainingTilesArray addObject:currentTile];
}
void (^myBlock)() = ^{
currentTile;
};
repeatCount++;
} while (repeatCount == 1);
Xcode 4.5.2、iOS 5、ARC を使用しています。また、LLVM コンパイラの最適化が「高速」以上に設定されている場合にのみクラッシュします。
上記のコードは、NSMutableArray からオブジェクトを取得して削除し、元に戻し、配列から別のオブジェクトを取得します。上記のコードはクラッシュせずに実行されますが、後で配列内のすべての要素をスキャンすると (たとえば、別のメソッドから)、クラッシュします。ランダムなメモリ アドレスが配列に追加されたようです (おそらく、上記の addObject の呼び出しから)。
上記のブロックは何もしないはずですが、変更しても後でクラッシュすることはありません。(たとえば、空のブロック = クラッシュなし。ブロックを "myBlock" として宣言しない = クラッシュなし。) ループを繰り返さない場合、クラッシュはありません。オブジェクトを追加し直さなければ、クラッシュはありません。__block を使用して、または do ループ内で currentTile を宣言すると、クラッシュは発生しません。
ブロックが「スタックローカル」であることは知っていますが、このブロックは何もしません! そして、コンパイラの最適化なしで問題なく動作します。
何が起こっているのか分かりますか?
編集 (12-5-12): 誰かがクラッシュ ログを要求しました。シミュレーターで実行しているので、それを取得する方法がわかりません。しかし、Debug Navigator から少しだけ抜粋します。
#0 0x0140409b in objc_msgSend ()
#1 0x00010931 in __33-[GCFGame checkThatTilesAreValid]_block_invoke_0 at /Users/geoffrey2/personal/projects/Color Fever/Color Fever/GCFGame.m:54
#2 0x01cb24a5 in __NSArrayEnumerate ()
#3 0x01cb2026 in -[NSArray enumerateObjectsWithOptions:usingBlock:] ()
#4 0x01cb1f35 in -[NSArray enumerateObjectsUsingBlock:] ()
#5 0x000108f6 in -[GCFGame checkThatTilesAreValid] at /Users/geoffrey2/personal/projects/Color Fever/Color Fever/GCFGame.m:52
メインウィンドウにはこれが表示されます(さらに多くの行が表示されます):
libobjc.A.dylib`objc_msgSend:
0x140408c: movl 8(%esp), %ecx
0x1404090: movl 4(%esp), %eax
0x1404094: testl %eax, %eax
0x1404096: je 0x14040e8 ; objc_msgSend + 92
0x1404098: movl (%eax), %edx
0x140409a: pushl %edi
0x140409b: movl 8(%edx), %edi
エラーはEXC_BAD_ACCESS(code=2, adddress=0x9).