先定个小目标,例如整理一篇关于 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
参考资料