块和ARC – 使用发布版本复制或崩溃(由优化级别引起)
我正在使用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); } }
调试它,调用优化级别设置为“None”的setCallbackBlock,传入的块将是NSStackBlock
,并且callbackBlock将成为NSMallocBlock
。
然而,在优化级别“最快,最小”的情况下,它仍然是一个NSStackBlock
。
更改setter代码以使用[block copy]
修复崩溃问题(基于iOS 5块仅在Release Build中崩溃 )。
但是,另一个相关问题表明,ARC 不需要这样做 – 块变量被复制到ARC中的堆中 – 为什么Objective-C块仍然可以工作而不将其复制到堆中?
所以我的问题是:这里发生了什么,为什么? (另外,这两个答案如何才能正确……?)
编辑 :澄清如何声明callbackBlock – 就在我的@implementation之上,这些方法是这样的:
@interface MyClass () { void (^callbackBlock)(NSString *input); } @end
所以我的问题是:这里发生了什么,为什么? (另外,这两个答案如何才能正确……?)
我实际上认为另一个问题的答案是错误的,因为它没有回答关于ARC中的块的特定问题。 问题是将基于堆栈的块从一个函数/方法传递到另一个函数/方法。 答案是关于不同的东西,即在块中捕获__block变量。 这是一个不同的问题。
您的问题的答案在过渡到ARC发行说明的常见问题解答中:
在ARC模式下将块传递到堆栈时块“正常工作”,例如在返回中。 您不必再调用Block Copy。 将堆栈“向下”传递给arrayWithObjects:以及其他执行保留的方法时,仍需要使用[^ {} copy]。
因此,它的工作方式是,当您传递一个块(在您的情况下是在堆栈上分配的块文字)时,编译器在初始化该调用的参数时不会复制该块。 被调用的函数或方法有责任在需要时复制该块本身。
ARC从函数或方法返回块时自动复制块的位置。 在这种情况下,编译器知道它必须为您复制到堆,所以它确实如此。
因此,即使使用ARC,您的setter也应该进行块复制。
我希望有所帮助。
这是对Firoze答案的长篇评论。
文档自动引用计数“第7.5节规定:
除了作为初始化
__strong
参数变量或读取__weak
变量的一部分完成的保留外,每当这些语义调用保留块指针类型的值时,它都具有Block_copy
的效果。 当优化器看到结果仅用作调用的参数时,可以删除这些副本。
这就是我所看到的行为。
因此,如果callbackBlock
是一个强实例变量,那么ARC应该在block
复制任何堆栈分配的块传递。 即Debug版本是正确的,Release版本是编译器错误。
如果这是正确的,那么你发现了一个编译器错误,应该报告它。 无论哪种方式报告它都不会坏,它应该产生明确的答案。
- 把随机的UIButtons标题的NSMutableArray NSMutablearray的UIButtons
- YTPlayerView youtube-ios-player-helper暂停不工作
- 是否可以更改UITextView和UITextField中单个单词的颜色
- CGImage到UIImage不起作用
- 如何将iPhone应用程序与_every_文件types关联?
- 如何从已经在UINavigationController栈中的UIViewController调用一个方法
- NSCache objectForKey:在iOS 8上总是返回零后的内存警告
- 如何检测tableview单元格中的多个button
- iOS上的Autocad格式查看器