您的位置:首页 > 其它

文章标题1

2017-03-24 14:04 302 查看
block是如何实现的1

我们通过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_size
block的空间大小

__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* Desc
block的描述,主要描述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代码和之前的对照也只是在传参的地方有所不同,在实现和逻辑调用上并没有发生变化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: