然后我第一次运行该分析器,并且它几乎马上就开始崩溃 – 特别是在尝试调用第一个回调块时,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 blocks crash only with Release Build).
然而,另一个相关的问题表明,ARC-Why does Objective-C block still work without copying it to the heap?中的ARC – 块变量被复制到堆中不是必需的
所以我的问题:这里发生了什么,为什么? (另外,这两个答案如何正确??)
编辑:
要澄清如何声明callbackBlock – 就在我的@implementation之上,那些方法是这样的:
@interface MyClass () { void (^callbackBlock)(NSString *input); } @end
解决方法
So my question: What’s going on here,and why? (Also,how can both of those answers be correct…?)
我实际上认为the other question的答案是错误的,因为它没有回答关于ARC中的块的特定问题.问题是将一个基于堆栈的块从一个函数/方法传递给另一个.答案是一些不同的东西,这是捕获一个块内的__block变量.这是一个不同的问题.
您的问题的答案是Transitioning to ARC Release Notes:的常见问题
Blocks “just work” when you pass blocks up the stack in ARC mode,such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.
所以这样做的方式是,当你传递一个块(在你的情况下是在堆栈上分配的块文字)时,编译器在初始化该调用的参数时不会复制该块.被调用的函数或方法有责任在需要时复制该块本身.
当ARC从函数或方法返回块时,ARC自动复制块.在这种情况下,编译器知道它必须为你做一个复制到堆,所以它.
所以你的设置者应该做一个块拷贝,甚至用ARC.
我希望有帮助.