標籤:
block內部結構
讓我們寫一個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();}
用clang轉成c分析下
clang -rewrite-objc block.c
能夠看到他們的定義是
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 = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }};
初始化和運行代碼
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);}
我們先看看blockTest2,它是由 結構體impl, 結構體Desc, 構造方法__exampleBlock_block_impl_2() 組成展開後是
- *isa 指向該執行個體對象(代碼裡是NSConcreteStackBlock,事實上應該是NSConcreteGlobalBlock)
- Flags 用於按bit位表示一些block的附加資訊
- reserved 保留變數
- *FuncPtr 函數指標,指向詳細的block實現的函數調用地址(代碼裡是__exampleBlock_block_func_2)
static void __exampleBlock_block_func_2(struct __exampleBlock_block_impl_2 *__cself) { ;}
- size_t reserved 這個傳進來的是0
- Block_size 結構體的大小
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)};
然後我們在看blockTest,它比blockTest2多了2個變數a, b
在產生的初始化代碼中則多了3個傳入值
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);
__Block_byref_b_0這個結構體是
struct __Block_byref_b_0 { void *__isa;__Block_byref_b_0 *__forwarding; int __flags; int __size; int b;};
__forwarding 是一個指向自己的指標.
__Block_byref_b_0 的初始化代碼例如以下:
__attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 2};
我們能夠看出a是直接複製進去的,b是被轉到了一個結構體裡,然後吧這個結構體的指標傳進去,所以block不能改動a,能改動b.
blockTest0的Desc和blockTest2也有所不同,展開後是
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個函數指標copy, dispose,對於在調用前後改動對應變數的引用計數, 分別指向
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*/);}
再來看下blockTest0的*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; }
如可以看到的a使用輸入的副本a, b使用一種結構,其中b
著作權聲明:本文博主原創文章。部落格,未經同意不得轉載。
Objective-C block實現程式碼分析