Block实现

block是如何实现的

我们通过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代码和之前的对照也只是在传参的地方有所不同,在实现和逻辑调用上并没有发生变化。
发布了139 篇原创文章 · 获赞 35 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/wxs0124/article/details/65443448