为什么这样使用 dispatch_block_t 不安全?
Why is it not safe to use dispatch_block_t like this?
为什么这样使用dispatch_block_t不安全?
我正在阅读dispatch_block_t的官方评论,我发现了以下代码,我不明白哪里错了?为什么不安全?有人可以告诉我吗?我很感激。希望详细给我解释一下
#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__
以上代码摘录:
dispatch_block_t block;
if (x) {
block = ^{ printf("true\n"); };
} else {
block = ^{ printf("false\n"); };
}
block(); // unsafe!!!
我不明白哪里出了问题?为什么不安全?
这是不安全的,因为块不能保证在它们所在的复合语句结束后存在(即 if
语句的“then”子句和“else”子句。这个问题类似于如果你这样做会发生什么
char *fun(void) {
char str[] = "hello";
return str; // !!! returning a pointer to an array
// about to go out of scope!
}
请注意,像 dispatch_async() 这样的函数会自动将块复制到堆中,因此只要在块超出范围之前分派块,就可以了。
When not building with Objective-C ARC
在 ARC 中是安全的。而且我不知道你为什么会在2019年使用MRC
这里的文档有点混乱,因为它没有针对 ARC 进行全面更新。 Under ARC, this is all done for you automatically.
但至于为什么需要它,Objective-C 块最初分配在堆栈上。这在立即使用和丢弃它们的情况下提高了性能。如果它们逃脱了当前堆栈范围,则需要将它们复制到堆和内存中,就像 object 一样进行管理。这是使用 Block_copy()
或传递 -copy
手动完成的 (pre-ARC)。有关详细信息,请参阅 Blocks Tips & Tricks。
但是你的直觉是正确的;只要您使用的是 ARC,发布的代码就可以。如果它是当前 SDK 的一部分,您可能想要打开 Apple 反馈请求更新 header 以使其更加清晰。
为什么这样使用dispatch_block_t不安全?
我正在阅读dispatch_block_t的官方评论,我发现了以下代码,我不明白哪里错了?为什么不安全?有人可以告诉我吗?我很感激。希望详细给我解释一下
#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__
以上代码摘录:
dispatch_block_t block;
if (x) {
block = ^{ printf("true\n"); };
} else {
block = ^{ printf("false\n"); };
}
block(); // unsafe!!!
我不明白哪里出了问题?为什么不安全?
这是不安全的,因为块不能保证在它们所在的复合语句结束后存在(即 if
语句的“then”子句和“else”子句。这个问题类似于如果你这样做会发生什么
char *fun(void) {
char str[] = "hello";
return str; // !!! returning a pointer to an array
// about to go out of scope!
}
请注意,像 dispatch_async() 这样的函数会自动将块复制到堆中,因此只要在块超出范围之前分派块,就可以了。
When not building with Objective-C ARC
在 ARC 中是安全的。而且我不知道你为什么会在2019年使用MRC
这里的文档有点混乱,因为它没有针对 ARC 进行全面更新。 Under ARC, this is all done for you automatically.
但至于为什么需要它,Objective-C 块最初分配在堆栈上。这在立即使用和丢弃它们的情况下提高了性能。如果它们逃脱了当前堆栈范围,则需要将它们复制到堆和内存中,就像 object 一样进行管理。这是使用 Block_copy()
或传递 -copy
手动完成的 (pre-ARC)。有关详细信息,请参阅 Blocks Tips & Tricks。
但是你的直觉是正确的;只要您使用的是 ARC,发布的代码就可以。如果它是当前 SDK 的一部分,您可能想要打开 Apple 反馈请求更新 header 以使其更加清晰。