Awe*_*e-o 5 reference-counting objective-c ios objective-c-blocks
给出以下(手动引用计数):
void (^block)(void) = ^ {
NSLog(@"wuttup");
}
void (^async_block)(void) = ^ {
block();
}
dispatch_async(dispatch_get_main_queue(), async_block);
Run Code Online (Sandbox Code Playgroud)
将"阻止"复制而不是从堆栈中抛出并销毁?
我相信,答案是肯定的.
外部块将被异步调度,这会导致运行时在此块的堆上进行复制.如下所示,并在Block Implementation Specification - Clang 3.4 Documentation中描述,内部块的导入变量也被复制到堆中.
在OP的例子中,我们有一个"块引用的导入常量副本".
我正在使用规范中的示例:
void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();
Run Code Online (Sandbox Code Playgroud)
规范声明需要copy_helper和dispose_helper函数:
copy_helper函数既传递现有的基于堆栈的指针又传递指向新堆版本的指针,并应回调到运行时以实际对块内导入的字段执行复制操作.
规范中的以下示例代码难以解密(实际上缺少描述将外部块复制到堆时会发生什么).无论如何,看起来规范试图表明内部块的导入变量将(递归地)复制到外部块的原始存储区域中.
当外部块将被复制到堆上时,内部块的导入变量似乎最终也会存在于堆上.
嗯,直观地说,这一切都是有道理的.
我做了一个小测试程序,它将证明这一点:(你必须调试并检查反汇编,以便弄清楚表面下发生了什么).
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出如下:
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
Run Code Online (Sandbox Code Playgroud)
当块在主线程上执行时,它将存在于堆栈中(如本地和导入变量的地址所示).当通过dispatch_async运行时执行时,复制了块 - 包括内部块,可以通过块的本地和导入变量的地址看到.
我们可以在copy_helper_block函数上设置一个断点,实际上,程序在那里停止一次,以便将块复制vv到堆中.

| 归档时间: |
|
| 查看次数: |
1495 次 |
| 最近记录: |