先定個(gè)小目標(biāo),例如整理一篇關(guān)于 block 的筆記
-
先用 OC 寫一段最簡單的 block 代碼:
int main(int argc, const char * argv[]) { @autoreleasepool { void (^myBlock)(void) = ^{ NSLog(@"hello world"); } ; myBlock() ; } return 0; } 使用 clang -rewrite-objc 查看 block 的源代碼:
```objc
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)) ;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock) ;
}
return 0;
}
```
-
為了提高上述代碼的可讀性,將類型轉(zhuǎn)化的代碼去掉,變成如下代碼:
int main(){ (*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ; myBlock -> FuncPtr ; } -
現(xiàn)在讓我們來看下這兩句代碼的作用到底是什么
首先我們發(fā)現(xiàn),我們源代碼中代碼塊里面的代碼 “不見了”。在轉(zhuǎn)化后的代碼中,我們沒有找到代碼塊里面的。
^{ NSLog(@"hello world"); } ; -
我們先看
__mian_block_func_0這個(gè)參數(shù)到底是什么。查看 main.cpp 代碼可以發(fā)現(xiàn)原來它是個(gè)方法,參數(shù)為 self (代碼塊):static void __main_block_func_0(struct __main_block_impl_0 *__cself) { NSLog((NSString*)&__NSConstantStringImpl__var_folders_v4_lj0qxzgx4bn62svsmmv5gk240000gn_T_main_cc2878_mi_0); } -
由此我們可以知道我們代碼塊的內(nèi)容都保存在
__mian_block_func_0這個(gè)方法里面。然后作為參數(shù)傳遞到__main_block_impl_0這個(gè)方法里面。那么__main_block_impl_0這個(gè)方法又有什么作用呢?查看 mian.cpp 代碼可以發(fā)現(xiàn):struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; -
我們逐一介紹該方法中的代碼。
struct __block_impl impl
該代碼申明了一個(gè) block 。
__block_impl的具體內(nèi)容如下所示,可以看出 block 其實(shí)就是個(gè)結(jié)構(gòu)體:struct __block_impl { void *isa; // 指向?qū)ο笤?block 的類型 int Flags; // 該 block 的一些其他信息 int Reserved; // 保留區(qū) void *FuncPtr; // 該 block 指向的內(nèi)存地址 };struct __main_block_desc_0* Desc;
該代碼申明了一個(gè)關(guān)于該 block 的一些信息的方法。其實(shí)現(xiàn)如下所示:
static struct __main_block_desc_0 { size_t reserved; // 保留區(qū)的大小 size_t Block_size; // block 的大小 } __main_block_desc_0_DATA = { // 快速初始化方法 0, sizeof(struct __main_block_impl_0) };__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0)
該方法為
__main_block_impl_0的構(gòu)造函數(shù),主要為__block_impl類型創(chuàng)建的 block 賦值。- fp 指向前面所述的
__mian_block_func_0的地址 - desc 指向掐面所述的
__main_block_desc_0 - flag...
- fp 指向前面所述的
-
綜上所述,我們應(yīng)該能夠明白下面代碼的作用了,就是將創(chuàng)建一個(gè) block,初始化該結(jié)構(gòu)體,在構(gòu)造函數(shù)中傳入自身(self) __main_block_func_0 結(jié)構(gòu)體和基本信息。
(*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ; -
得到新創(chuàng)建的 block 后,當(dāng)我們調(diào)用原本代碼的 block時(shí)候,就相當(dāng)于調(diào)用:
myBlock -> FunPtr