ios - does dispatch_async copy internal blocks -
given following (manual reference counting):
void (^block)(void) = ^ { nslog(@"wuttup"); } void (^async_block)(void) = ^ { block(); } dispatch_async(dispatch_get_main_queue(), async_block);
will "block" copied rather thrown off stack , destroyed?
i believe, answer yes.
the outer block asynchronously dispatched causes runtime make copy on heap block. , shown below, , described in block implementation specification - clang 3.4 documentation, inner block's imported variables copied heap.
in op's example have "imported const copy of block reference".
i'm using example in specification:
void (^existingblock)(void) = ...; void (^vv)(void) = ^{ existingblock(); } vv();
the specification states copy_helper
, dispose_helper
functions needed:
the copy_helper function passed both existing stack based pointer , pointer new heap version , should call runtime copy operation on imported fields within block.
the following example code in specification difficult decipher (and lacks description happens when outer block copied heap). anyway, appears specification tries show imported variables of inner blocks (recursively) copied raw storage area of outer block.
when outer block copied on heap, seems imported variables of inner blocks live on heap well.
well, intuitively, makes sense.
i made small test program demonstrate this: (you have debug , examine disassembly in order figure out whats going on under surface).
#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; }
the output follows:
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
when block executed on main thread, lives on stack (as shown addresses of local , imported variables). when executed via dispatch_async
runtime has copied block - including inner blocks, can seen addresses of local , imported variables of blocks.
we can set breakpoint @ copy_helper_block
function, , in fact, program stops there once, in order copy block vv
heap.
Comments
Post a Comment