Block internal structure
Let's write a block
void Exampleblock () { //nsconcretestackblock int a = 1; __block int b = 2; Int (^blocktest0) (int c) = ^ (int c) { return a + B + C; }; int c = 3; BlockTest0 (c); Nsconcreteglobalblock Void (^blocktest2) (void) = ^ (void) { ; }; BlockTest2 ();}
Turn the clang into C analysis.
CLANG-REWRITE-OBJC BLOCK.C
To be able to see that their definition is
struct __exampleblock_block_impl_0 {struct __block_impl impl; struct __exampleblock_block_desc_0* desc; int A; __block_byref_b_0 *b; By ref __exampleblock_block_impl_0 (void *fp, struct __exampleblock_block_desc_0 *desc, int _a, __block_byref_b_0 *_b, int flags=0): A (_a), B (_b->__forwarding) {Impl.isa = &_NSConcreteStackBlock; Impl. Flags = flags; Impl. funcptr = FP; desc = desc; }};//__block_implstruct __block_impl {void *isa; int Flags; int Reserved; void *funcptr;};/ /__exampleblock_block_desc_0struct __exampleblock_block_impl_0 {struct __block_impl impl; struct __exampleblock_block_desc_0* desc; int A; __block_byref_b_0 *b; By ref __exampleblock_block_impl_0 (void *fp, struct __exampleblock_block_desc_0 *desc, int _a, __block_byref_b_0 *_b, int flags=0): A (_a), B (_b->__forwarding) {Impl.isa = &_NSConcreteStackBlock; Impl. Flags = flags; Impl. funcptr = FP; desc = desc; }};//__exampleblock_block_impl_2struct __exampleblock_block_impl_2 {struct __block_impl impl; struct __exampleblock_block_desc_2* desc; __exampleblock_block_impl_2 (void *fp, struct __exampleblock_block_desc_2 *desc, int flags=0) {Impl.isa = &_NSCONCR Etestackblock; Impl. Flags = flags; Impl. funcptr = FP; desc = desc; }};
Initializing and running code
void Exampleblock () { //blockTest0 int a = 1; __ATTRIBUTE__ ((__blocks__ (ByRef))) __block_byref_b_0 B = {(void*) 0, (__BLOCK_BYREF_B_0 *) &b, 0, sizeof (__block_ BYREF_B_0), 2}; Int (*blocktest0) (int c) = (int (*) (int)) &__exampleblock_block_impl_0 ((void *) __exampleblock_block_func_0, &_ _exampleblock_block_desc_0_data, A, (__BLOCK_BYREF_B_0 *) &b, 570425344); int c = 3; ((Int (*) (__BLOCK_IMPL *, int)) ((__block_impl *) blockTest0)->funcptr) ((__block_impl *) blockTest0, c); BlockTest2 Void (*blocktest2) (void) = (void (*) ()) &__exampleblock_block_impl_2 ((void *) __exampleblock_ block_func_2, &__exampleblock_block_desc_2_data); ((Void (*) (__block_impl *)) ((__block_impl *) blockTest2)->funcptr) ((__block_impl *) blockTest2);}
Let's take a look at BlockTest2, which is composed of structural bodies IMPL, structure desc, construction method __exampleblock_block_impl_2 ()
- *isa points to the instance object (the code is Nsconcretestackblock, in fact it should be Nsconcreteglobalblock)
- Flags are used to indicate additional information about the block by bit bit
- Reserved reserved variables
- *funcptr function Pointer to the detailed block implementation of the function call address (in the code is __exampleblock_block_func_2)
static void __exampleblock_block_func_2 (struct __exampleblock_block_impl_2 *__cself) { ;}
- size_t reserved, this one came in 0.
- Size of the BLOCK_SIZE structure
static struct __exampleblock_block_desc_2 { size_t reserved; size_t Block_size;} __exampleblock_block_desc_2_data = {0, sizeof (struct __exampleblock_block_impl_2)};
And then we're looking at Blocktest, which is 2 more variables A, b than blockTest2.
int A; External variable A,
Block_byref_b_0 *b, with a Block-modified B . Block_byref_b_0
3 more incoming values in the generated initialization code
Int (*blocktest0) (int c) = (int (*) (int)) &__exampleblock_block_impl_0 ((void *) __exampleblock_block_func_0, &_ _exampleblock_block_desc_0_data, A, (__BLOCK_BYREF_B_0 *) &b, 570425344);
A is that this is directly passed in and then copied to a
b is the address of the transfer, is to assign the __block_byref_b_0 to B
__BLOCK_BYREF_B_0 This structure is
struct __BLOCK_BYREF_B_0 { void *__isa;__block_byref_b_0 *__forwarding; int __flags; int __size; int b;};
__forwarding is a pointer to itself.
The initialization code for __BLOCK_BYREF_B_0 is as follows:
__ATTRIBUTE__ ((__blocks__ (ByRef))) __block_byref_b_0 B = {(void*) 0, (__BLOCK_BYREF_B_0 *) &b, 0, sizeof (__block_ BYREF_B_0), 2};
We can see that a is directly copied in, B is transferred to a structure, and then the structure of the pointer passed in, so block can not change a, can change B.
- 570425344 This should be passed to flags.
BLOCKTEST0 's desc and blockTest2 are also different, after unfolding is
static struct __exampleblock_block_desc_0 { size_t reserved; size_t block_size; void (*copy) (struct __exampleblock_block_impl_0*, struct __exampleblock_block_impl_0*); void (*dispose) (struct __exampleblock_block_impl_0*);} __exampleblock_block_desc_0_data = {0, sizeof (struct __exampleblock_block_impl_0), __exampleblock_block_copy_0, __ EXAMPLEBLOCK_BLOCK_DISPOSE_0};
2 more function pointers Copy, Dispose, for changing the reference count of the corresponding variable before and after the call, pointing to
static void __exampleblock_block_copy_0 (struct __exampleblock_block_impl_0*dst, struct __exampleblock_block_impl_0* SRC) {_block_object_assign ((void*) &dst->b, (void*) src->b, 8/*block_field_is_byref*/);} static void __exampleblock_block_dispose_0 (struct __exampleblock_block_impl_0*src) {_block_object_dispose ((void*) Src->b, 8/*block_field_is_byref*/);}
And look at BlockTest0 's *funcptr.
static int __exampleblock_block_func_0 (struct __exampleblock_block_impl_0 *__cself, int c) { __block_byref_b_0 *b = __cself->b; Bound by ref Int. A = __cself->a;//bound by copy return a + (b->__forwarding->b) + C; }
If you can see that a uses the input copy of A, B uses a structure where b
Copyright notice: This article Bo Master original article. Blog, not reproduced without consent.
Objective-c block Implementation Code Analysis