文章标题1
2017-03-24 14:04
302 查看
block是如何实现的1
我们通过clang编译出Objective-C文件对应cpp文件,去看他的实现方式,对比不同样式的
从中得到它的实现思想
我们在ViewController.m中声明,实现并使用一个不带参数的Block
然后通过clang编译出对应的cpp文件,我们只关心和Block对应的代码,如下
我们来解析一下
这个结构体的作用相当于是一个block的“核心功能类”,包含指向superclass的指针,
执行方法的指针。
看到impl这个应该是对应Implements,见名知意我们可以理解为声明一个block对应的类
这个我们看后边能否解答。
中间的就不用说了,NSLog。。
通过clang编译后:
我们通过clang编译出Objective-C文件对应cpp文件,去看他的实现方式,对比不同样式的
block的不同,
从中得到它的实现思想
无参数Block的基本实现
#import "ViewController.h" typedef void(^WxsBlock) (); @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; WxsBlock blockObj = ^(){ NSLog(@"test"); }; blockObj(); } @end
我们在ViewController.m中声明,实现并使用一个不带参数的Block
然后通过clang编译出对应的cpp文件,我们只关心和Block对应的代码,如下
typedef void(*WxsBlock) (); struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }; struct __ViewController__viewDidLoad_block_impl_0 { struct __block_impl impl; struct __ViewController__viewDidLoad_block_desc_0* Desc; __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_dd8c22_mi_0); } static struct __ViewController__viewDidLoad_block_desc_0 { size_t reserved; size_t Block_size; } __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)}; static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) { ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad")); WxsBlock blockObj = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA)); ((void (*)(__block_impl *))((__block_impl *)blockObj)->FuncPtr)((__block_impl *)blockObj); }
我们来解析一下
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }
这个结构体的作用相当于是一个block的“核心功能类”,包含指向superclass的指针,
执行方法的指针。
void *isa指向superclass的指针,在Objective-C中Block也是对象,这个就不难理解了
int Flags标记,这个不知道有什么深意,暂且我们理解为做一个标记的作用。
int Reserved预留字段,现在不必关心,不过这种预留的思想可以学习
void *FuncPtr要执行方法的指针,这个是用来持有block代码块中方法的指针
static struct __ViewController__viewDidLoad_block_desc_0 { size_t reserved; size_t Block_size; } __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)};
__ViewController__viewDidLoad_block_desc_0看名字,这是一个用来描述block的,
size_t reserved预留的空间大小
size_t Block_sizeblock的空间大小
__ViewController__viewDidLoad_block_desc_0_DATA声明的结构体变量,参数是
reserved = 0
Block_size是
__ViewController__viewDidLoad_block_impl_0的大小
struct __ViewController__viewDidLoad_block_impl_0 { struct __block_impl impl; struct __ViewController__viewDidLoad_block_desc_0* Desc; __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }
看到impl这个应该是对应Implements,见名知意我们可以理解为声明一个block对应的类
struct __block_impl impl就是我们上边描述的“核心类”
struct __ViewController__viewDidLoad_block_desc_0* Descblock的描述,主要描述block所占空间大小Block_size
__ViewController__viewDidLoad_block_impl_0是此结构体的一个构造函数
void *fp构造函数第一个参数,执行函数指针,赋值给
impl变量的
funcPtr指针
struct __ViewController__viewDidLoad_block_desc_0 *desc这里又作为构造函数的第二个参数,赋值给
Desc变量
int flags=0同上,赋值给
impl中的
Flags变量,但这有趣的是,它默认为0,深意自咎,因为我也猜不出来。。
impl.isa = &_NSConcreteStackBlock;这个对应的还有
_NSConcreteGlobalBlock
_NSConcreteMallocBlock这里我们只需要知道它对应的是在栈上的block,其他的我们后边解析
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_dd8c22_mi_0); }
static void __ViewController__viewDidLoad_block_func_0静态block执行函数,也就是我们在
{}中的
NSLog那一段。
struct __ViewController__viewDidLoad_block_impl_0 *__cself)参数是我们刚才提到的
impl“核心功能类”,但是奇怪的是它并没有在函数体中使用,
这个我们看后边能否解答。
中间的就不用说了,NSLog。。
WxsBlock blockObj = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA));
(void (*)())标示无返回值的匿名函数指针,并且函数没有参数,这也正对应了我们前边的
typedef void(*WxsBlock) ();block声明
&这个取地址符我有点懵逼,来个懂C的大神指点一下(ps:默默的去看看大学的C课本。。),虽然看不懂,但是不影响我们的整体解读。
__ViewController__viewDidLoad_block_impl_0是
__ViewController__viewDidLoad_block_impl_0结构体的一个构造函数,也就是我们定义的block的一个构造函数。参数上边有说。
__ViewController__viewDidLoad_block_func_0里边是
NSLog...的那个函数指针,也就是我们在block体中写的代码逻辑指针。
__ViewController__viewDidLoad_block_desc_0_DATA是
__ViewController__viewDidLoad_block_desc_0声明是创建的一个描述对象
带参数Block实现
在.m文件中:typedef void(^WxsBlock) (NSString *str,NSArray *arr); - (void)viewDidLoad { [super viewDidLoad]; WxsBlock blockObj = ^(NSString *str,NSArray *arr){ NSLog(@"test"); }; blockObj(@"wxs",[NSArray array]); }
通过clang编译后:
typedef void(*WxsBlock) (NSString *str,NSArray *arr);
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself, NSString *str, NSArray *arr) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_cf62af_mi_0);
}
static struct __ViewController__viewDidLoad_block_desc_0 { size_t reserved; size_t Block_size; } __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)};
static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));
WxsBlock blockObj = ((void (*)(NSString *, NSArray *))&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA));
((void (*)(__block_impl *, NSString *, NSArray *))((__block_impl *)blockObj)->FuncPtr)((__block_impl *)blockObj, (NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_cf62af_mi_1, ((NSArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSArray"), sel_registerName("array")));
}
通过对比看出,我们加入了两个参数,编译出来的cpp代码和之前的对照也只是在传参的地方有所不同,在实现和逻辑调用上并没有发生变化。