简体   繁体   English

为什么这样使用dispatch_block_t是不安全的?

[英]Why is it not safe to use dispatch_block_t like this?

Why is it not safe to use dispatch_block_t like this? 为什么这样使用dispatch_block_t是不安全的?

I am reading the official comment of dispatch_block_t, I found the following code, I don't understand what is wrong? 我正在阅读dispatch_block_t的官方评论,我发现以下代码,我不明白有什么问题? Why is it not safe? 为什么不安全? Can someone tell me? 有人能告诉我吗? I am very grateful. 我很感激。 I hope to explain to me in detail. 我希望向我详细解释。

#ifdef __BLOCKS__
/*!
 * @typedef dispatch_block_t
 *
 * @abstract
 * The type of blocks submitted to dispatch queues, which take no arguments
 * and have no return value.
 *
 * @discussion
 * When not building with Objective-C ARC, a block object allocated on or
 * copied to the heap must be released with a -[release] message or the
 * Block_release() function.
 *
 * The declaration of a block literal allocates storage on the stack.
 * Therefore, this is an invalid construct:
 * <code>
 * dispatch_block_t block;
 * if (x) {
 *     block = ^{ printf("true\n"); };
 * } else {
 *     block = ^{ printf("false\n"); };
 * }
 * block(); // unsafe!!!
 * </code>
 *
 * What is happening behind the scenes:
 * <code>
 * if (x) {
 *     struct Block __tmp_1 = ...; // setup details
 *     block = &__tmp_1;
 * } else {
 *     struct Block __tmp_2 = ...; // setup details
 *     block = &__tmp_2;
 * }
 * </code>
 *
 * As the example demonstrates, the address of a stack variable is escaping the
 * scope in which it is allocated. That is a classic C bug.
 *
 * Instead, the block literal must be copied to the heap with the Block_copy()
 * function or by sending it a -[copy] message.
 */
typedef void (^dispatch_block_t)(void);
#endif // __BLOCKS__

Excerpt from the above code: 以上代码摘录:

dispatch_block_t block;
if (x) {
    block = ^{ printf("true\n"); };
} else {
    block = ^{ printf("false\n"); };
}
block(); // unsafe!!!

I don't understand what is wrong? 我不明白有什么不对? Why is it not safe? 为什么不安全?

The documentation here is a little confusing, since it wasn't fully updated for ARC. 这里的文档有点令人困惑,因为ARC没有完全更新。 Under ARC, this is all done for you automatically. 在ARC下,这一切都是自动完成的。

But as to why it's required, Objective-C blocks are initially allocated on the stack. 但至于为什么需要它,Objective-C块最初是在堆栈上分配的。 This improves performance in cases where they are immediately used and discarded. 这可以在立即使用和丢弃它们的情况下提高性能。 If they escape the current stack scope, then they need to be copied to the heap and memory managed like an object. 如果它们逃离当前的堆栈范围,则需要将它们复制到堆中,并像对象一样管理内存。 This is done manually (pre-ARC) using Block_copy() or passing -copy . 这是使用Block_copy()或传递-copy手动完成(预ARC)。 See Blocks Tips & Tricks for more on that. 有关详细信息,请参阅块提示和技巧

But your intuition here is correct; 但你的直觉是正确的; the posted code is fine as long as you're using ARC. 只要您使用ARC,发布的代码就可以了。 You may want to open an Apple Feedback to request this header be updated to be more clear if it's part of the current SDK. 如果它是当前SDK的一部分,您可能需要打开Apple反馈以请求更新此标题以使其更清晰。

It is unsafe because the blocks are not guaranteed to exist after the end of the compound statement that they are in (ie, the “then” clause and the “else” clause of the if statement. The problem is similar to what happens if you do 它是不安全的,因为在它们所在的复合语句结束后(即if语句的“then”子句和“else”子句,不保证块存在。问题类似于如果你发生的情况做

char *fun(void) {
    char str[] = "hello";
    return str; // !!! returning a pointer to an array
                // about to go out of scope!
}

Notice that functions like dispatch_async() automatically copy the block to the heap, so as long as you dispatch the block before it goes out of scope, you're fine. 请注意,像dispatch_async()这样的函数会自动将块复制到堆中,因此只要在块超出范围之前调度块,就可以了。

When not building with Objective-C ARC 不使用Objective-C ARC构建时

It's safe in ARC. 它在ARC中很安全。 And I don't know why you will use MRC in 2019 我不知道为什么你会在2019年使用MRC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM