块和ARC-版本发布导致复制或崩溃(由优化级别引起) [英] blocks and ARC - copy or crash with release build (caused by optimization level)

查看:63
本文介绍了块和ARC-版本发布导致复制或崩溃(由优化级别引起)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Xcode 4.3.3并为iOS 5.0+开发.在开发ARC iOS应用程序时,我已经开始使用块作为异步操作的回调机制.该应用程序在模拟器和设备上均可正常运行.

I'm using Xcode 4.3.3 and developing for iOS 5.0+. In development of an ARC iOS application, I've started using blocks as a callback mechanism for asynchronous operations. The app works fine in the simulator and on the device.

然后,我第一次运行它的探查器,并且它几乎立即就崩溃了,特别是在尝试调用第一个回调块时出现了EXC_BAD_ACCESS.

Then I ran it the profiler for the first time, and it started crashing on me nearly right away - in particular, an EXC_BAD_ACCESS when trying to invoke the first callback block.

经过一番调查,很明显,行为上的差异是因为探查器默认情况下在发布模式"下运行-特别是,优化级别设置为最快,最小[-Os]",而不是无[ -O0]".

After a little investigation, it was clear the difference in behavior was because the profiler runs in "Release mode" by default - in particular, with Optimization Level set to "Fastest, Smallest [-Os]" instead of "None [-O0]".

例如,以下代码(针对此问题进行了简化)在尝试执行callbackBlock时将崩溃:

For example, the following code (simplified for this question) would crash when trying to execute the callbackBlock:

- (void) setCallbackBlock:(void (^)(NSString *input))block
{
    callbackBlock = block;
}

- (void) invokeCallbackWithInput:(NSString *)input
{
    if (callbackBlock) {
        callbackBlock(input);
    }
}

进行调试,调用setCallbackBlock并将优化级别设置为"None",传入的块将是NSStackBlock,而callbackBlock将成为NSMallocBlock.

Debugging into it, calling setCallbackBlock with optimization level set to "None", the incoming block would be an NSStackBlock, and the callbackBlock would become an NSMallocBlock.

但是,优化级别为最快,最小",它仍然是NSStackBlock.

However, with Optimization Level "Fastest, Smallest", it remained an NSStackBlock.

更改设置程序代码以使用[block copy]可以解决崩溃问题(基于

Changing the setter code to use [block copy] fixes the crashing problem (based on iOS 5 blocks crash only with Release Build).

但是,另一个相关问题表明,对于ARC,这不是必需的-将块变量复制到ARC中的堆中-

However, another related question indicates that this shouldn't be necessary with ARC - block variables are copied to the heap in ARC - Why does Objective-C block still work without copying it to the heap?

所以我的问题是:这是怎么回事,为什么呢? (而且,这两个答案怎么都正确??)

So my question: What's going on here, and why? (Also, how can both of those answers be correct...?)

修改: 为了澄清如何声明callbackBlock-在我的@implementation上方,这些方法是这样的:

Edit: To clarify how callbackBlock is being declared - just above my @implementation where those methods are is this:

@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...?)

我实际上认为

I actually think the answer to the other question is wrong, in that it doesn't answer that particular question about blocks in ARC. The question is about passing a stack based block from one function/method to another. The answer is about something different, which is capturing __block variables within a block. That's a different issue.

问题的答案在过渡到ARC发行说明:

在ARC模式下(例如在返回中)向上传递堆栈时,阻止正常工作".您无需再致电阻止复制".将堆栈向下"传递到arrayWithObjects:以及执行保留的其他方法时,仍然需要使用[^ {} copy].

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.

所以这种方法的工作方式是,当您传递一个块(在您的情况下是分配给堆栈的块文字)时,编译器在初始化该调用的参数时不会复制该块.如果需要,被调用的函数或方法负责复制该块本身.

So the way this works is that when you pass a block (in your case a block literal allocated on the stack), the compiler does not copy that block when it initializes the parameter for that call. The called function or method has the responsibility to copy that block itself if needed.

当您从功能或方法中返回块时,ARC会自动复制块.在这种情况下,编译器知道它必须必须为您做一个复制到堆的操作,

Where ARC does copy blocks automatically is when you are returning a block from a function or method. In that case, the compiler knows that it must do a copy to the heap for you, and so it does.

因此,即使使用ARC,您的安装员也应该进行块复制.

So your setter should be doing a block copy, even with ARC.

我希望能帮上忙.

这篇关于块和ARC-版本发布导致复制或崩溃(由优化级别引起)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆