私は Xcode 4.3.3 を使用しており、iOS 5.0 以降向けに開発しています。ARC iOS アプリケーションの開発では、ブロックを非同期操作のコールバック メカニズムとして使用し始めました。アプリはシミュレーターとデバイスで正常に動作します。
次に、初めてプロファイラーを実行しましたが、すぐにクラッシュし始めました。特に、最初のコールバック ブロックを呼び出そうとすると、EXC_BAD_ACCESS が発生しました。
少し調査した結果、動作の違いは、プロファイラーがデフォルトで「リリース モード」で実行されるためであることが明らかになりました。特に、最適化レベルが「なし [-O0]」ではなく「最速、最小 [-Os]」に設定されています。 "。
たとえば、次のコード (この質問のために簡略化されています) は、callbackBlock を実行しようとするとクラッシュします。
- (void) setCallbackBlock:(void (^)(NSString *input))block
{
callbackBlock = block;
}
- (void) invokeCallbackWithInput:(NSString *)input
{
if (callbackBlock) {
callbackBlock(input);
}
}
それにデバッグし、最適化レベルを「なし」に設定して setCallbackBlock を呼び出すと、着信ブロックは にNSStackBlock
なり、 callbackBlock は になりますNSMallocBlock
。
ただし、最適化レベル「最速、最小」では、NSStackBlock
.
setter コードを使用するように変更すると[block copy]
、クラッシュの問題が修正されます (リリース ビルドでのみ iOS 5 のブロックがクラッシュすることに基づきます)。
ただし、別の関連する質問は、これは ARC では必要ないことを示しています - ブロック変数は ARC のヒープにコピーされます -なぜ Objective-C ブロックはヒープにコピーしなくても機能するのですか?
私の質問: ここで何が起こっているのか、なぜですか? (また、どうして両方の答えが正しいのでしょうか...?)
編集: callbackBlock がどのように宣言されているかを明確にするために、これらのメソッドがある @implementation のすぐ上にあるのは次のとおりです。
@interface MyClass ()
{
void (^callbackBlock)(NSString *input);
}
@end