iOS--Block
先定個小目標,例如整理一篇關於 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;
}
```
-
為了提高上述程式碼的可讀性,將型別轉化的程式碼去掉,變成如下程式碼:
int main(){ (*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ; myBlock -> FuncPtr ; }
-
現在讓我們來看下這兩句程式碼的作用到底是什麼
首先我們發現,我們原始碼中程式碼塊裡面的程式碼 “不見了”。在轉化後的程式碼中,我們沒有找到程式碼塊裡面的。
^{ NSLog(@"hello world"); } ;
-
我們先看
__mian_block_func_0
這個引數到底是什麼。檢視 main.cpp 程式碼可以發現原來它是個方法,引數為 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); }
-
由此我們可以知道我們程式碼塊的內容都儲存在
__mian_block_func_0
這個方法裡面。然後作為引數傳遞到__main_block_impl_0
這個方法裡面。那麼__main_block_impl_0
這個方法又有什麼作用呢?檢視 mian.cpp 程式碼可以發現: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
該程式碼申明瞭一個 block 。
__block_impl
的具體內容如下所示,可以看出 block 其實就是個結構體:struct __block_impl { void *isa; // 指向物件該 block 的型別 int Flags; // 該 block 的一些其他資訊 int Reserved; // 保留區 void *FuncPtr; // 該 block 指向的記憶體地址 };
struct __main_block_desc_0* Desc;
該程式碼申明瞭一個關於該 block 的一些資訊的方法。其實現如下所示:
static struct __main_block_desc_0 { size_t reserved; // 保留區的大小 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
的建構函式,主要為__block_impl
型別建立的 block 賦值。- fp 指向前面所述的
__mian_block_func_0
的地址 - desc 指向掐面所述的
__main_block_desc_0
- flag...
- fp 指向前面所述的
-
綜上所述,我們應該能夠明白下面程式碼的作用了,就是將建立一個 block,初始化該結構體,在建構函式中傳入自身(self) __main_block_func_0 結構體和基本資訊。
(*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ;
-
得到新建立的 block 後,當我們呼叫原本程式碼的 block時候,就相當於呼叫:
myBlock -> FunPtr