我正在使用 Xcode 4.3.3 并为 iOS 5.0+ 进行开发。在开发 ARC iOS 应用程序时,我开始使用块作为异步操作的回调机制。该应用程序在模拟器和设备上运行良好。
然后我第一次运行探查器,它几乎马上就开始在我身上崩溃——特别是在尝试调用第一个回调块时出现 EXC_BAD_ACCESS。
经过一番调查,很明显行为上的差异是因为探查器默认以“发布模式”运行 - 特别是优化级别设置为“最快,最小 [-Os]”而不是“无 [-O0] ”。
例如,以下代码(针对此问题进行了简化)在尝试执行 callbackBlock 时会崩溃:
- (void) setCallbackBlock:(void (^)(NSString *input))block
{
callbackBlock = block;
}
- (void) invokeCallbackWithInput:(NSString *)input
{
if (callbackBlock) {
callbackBlock(input);
}
}
调试它,调用 setCallbackBlock 并将优化级别设置为“None”,传入的块将是一个NSStackBlock
,callbackBlock 将成为一个NSMallocBlock
。
但是,在优化级别“最快、最小”的情况下,它仍然是NSStackBlock
.
更改 setter 代码以使用[block copy]
修复了崩溃问题(基于iOS 5 块仅使用 Release Build 崩溃)。
但是,另一个相关问题表明,ARC 不需要这样做 - 块变量被复制到 ARC 中的堆中 -为什么 Objective-C 块在不将其复制到堆的情况下仍然可以工作?
所以我的问题是:这里发生了什么,为什么?(另外,这两个答案怎么可能是正确的......?)
编辑:为了澄清 callbackBlock 是如何被声明的——就在我的@implementation 上面这些方法是这样的:
@interface MyClass ()
{
void (^callbackBlock)(NSString *input);
}
@end