dispatch_async复制内部块

鉴于以下(手动引用计数):

void (^block)(void) = ^ { NSLog(@"wuttup"); } void (^async_block)(void) = ^ { block(); } dispatch_async(dispatch_get_main_queue(), async_block); 

将“块”复制,而不是从堆叠中被摧毁?

我相信答案是肯定的

外部块将被asynchronous调度,从而导致运行时在堆上为该块创build一个副本。 如下所示,并在块实现规范 – Clang 3.4文档中描述 ,内部块的导入variables也被复制到堆中。

在OP的例子中,我们有一个“块引用的导入const副本”。

我正在使用规范中的示例:

 void (^existingBlock)(void) = ...; void (^vv)(void) = ^{ existingBlock(); } vv(); 

规范指出需要copy_helperdispose_helper函数:

copy_helper函数同时传递现有的基于堆栈的指针和指向新堆版本的指针,并且应该调用回运行时间来实际上对块中导入的字段执行复制操作。

规范中的以下示例代码很难解密(实际上缺less描述将外部块复制到堆时发生的情况)。 无论如何,看起来规范试图显示内部块的导入variables将(recursion)复制到外部块的原始存储区域。

当外部块被复制到堆上时,看起来内部块的导入variables最终也会在堆上生存。

那么,直观地说,这一切都是有道理的。

我做了一个小的testing程序,它将certificate这一点:(你必须debugging和检查拆卸,以弄清楚表面下发生了什么)。

 #import <Foundation/Foundation.h> void foo(int param) { int x0 = param; int x1 = param + 1; void (^existingBlock)(void) = ^{ int y0 = x0; int y1 = x1; printf("&y0: %p\n", &y0); printf("&y1: %p\n", &y1); printf("&x0: %p\n", &x0); printf("&x1: %p\n", &x1); }; void (^vv)(void) = ^{ int y2 = x0; int y3 = x1; existingBlock(); printf("&y2: %p\n", &y2); printf("&y3: %p\n", &y3); printf("&x0: %p\n", &x0); printf("&x1: %p\n", &x1); }; printf("Stack: &x: %p\n", &x0); printf("Stack: &x: %p\n", &x1); printf("------- on main thread -------\n"); vv(); dispatch_async(dispatch_get_global_queue(0, 0), ^{ printf("------- on thread 2 -------\n"); assert(vv); sleep(1); int y4 = x0; int y5 = x1; vv(); printf("&y4: %p\n", &y4); printf("&y5: %p\n", &y5); printf("&x0: %p\n", &x0); printf("&x1: %p\n", &x1); }); } int main(int argc, const char * argv[]) { @autoreleasepool { foo(1); sleep(2); } return 0; } 

输出如下:

 Stack: &x: 0x7fff5fbff868 Stack: &x: 0x7fff5fbff864 ------- on main thread ------- &y0: 0x7fff5fbff70c &y1: 0x7fff5fbff708 &x0: 0x1001081e0 &x1: 0x1001081e4 &y2: 0x7fff5fbff76c &y3: 0x7fff5fbff768 &x0: 0x10010a588 &x1: 0x10010a58c ------- on thread 2 ------- &y0: 0x1000e5d9c &y1: 0x1000e5d98 &x0: 0x1001081e0 &x1: 0x1001081e4 &y2: 0x1000e5dfc &y3: 0x1000e5df8 &x0: 0x10010a588 &x1: 0x10010a58c &y4: 0x1000e5e6c &y5: 0x1000e5e68 &x0: 0x10010a5e8 &x1: 0x10010a5ec 

当在主线程上执行该块时,该块位于堆栈上(如本地variables和导入variables的地址所示)。 当通过dispatch_async执行时,运行时复制了块(包括内部块),这可以通过块的本地variables和导入variables的地址来看到。

我们可以在copy_helper_block函数中设置一个断点,实际上,程序停在那里一次,以便将块vv复制到堆中。

在这里输入图像说明

dispatch_async上的Apple文档 :

The block to submit to the target dispatch queue. This function performs Block_copy and Block_release on behalf of callers. This parameter cannot be NULL.

所以, async_block被复制。

根据这个讨论 , blockasync_block在你的例子中)将是async_block中的一个readonly copy

如同普通对象一样, blockretain (不会被复制到每个块)作为另一个块的async_block 。 该块的复制是块对象被发送的一个[block retain]消息的结果,该消息调用复制该块的重写retain方法。

    Interesting Posts