到底什么是block?

2021-04-21  本文已影响0人  水蜜桃看看就好

简述Block

block 是 C 语言的扩充功能,我们可以认为它是 带有自动变量的匿名函数,同时也是一个对象。

1 标准定义
returnType(^blockName)(var_type) = ^returnType(var_type varName){ //操作 }
举个🌰 :
void(^defalutBlock)(NSString *) = ^void(NSString *name){ NSlog(@"%@",name)}

2 省略缩写
returnType(^blockName)(var_type) = ^(var_type varName){ //操作 }
举个🌰 :
void(^defalutBlock)(NSString *) = ^(NSString *name){ NSlog(@"%@",name)}

3 typedef简化Block的声明
typedef return_type (^BlockTypeName)(var_type);

1.block的原理是怎样的?本质是什么?
2.__block的作用是什么?有什么使用注意点?
3.block的属性修饰词为什么是copy?使用block有哪些使用注意?
4.block在修改NSMutableArray,需不需要添加__block

问题1: block原理是什么?本质是什么?

写个block

int main(int argc, char * argv[]) {
    int(^block)(int)=^int(int a)
    {
        return  a;
    };
    block(8);
    
    return  0;
}

通过使用clang命令,将.m文件转换成.cpp文件clang -rewrite-objc main.m

int main(int argc, char * argv[]) {

    int(*block)(int)=((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    ((int (*)(__block_impl *, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 8);

    return 0;
}

C++定义block变量代码 其中不难看出 将__main_block_impl_0函数的地址赋值给了block

 int(*block)(int)=((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

我们接着看下__main_block_impl_0是什么?是一个结构体

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;
  }
};

注意:__main_block_impl_0结构体中 有同名的构造函数__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) 其中的fp 可以理解为方法的地址

我们可以看到__main_block_desc_0中存储着两个参数,reserved和Block_size,并且reserved赋值为0而Block_size则存储着__main_block_impl_0的占用空间大小。最终将__main_block_desc_0结构体的地址传入__main_block_func_0中赋值给Desc

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

我们再来看下__block_impl结构体

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

我们可以发现__block_impl结构体内部就有一个isa指针。因此可以证明block本质上就是一个oc对象。而在构造函数中将函数中传入的值分别存储在__main_block_impl_0结构体实例中,最终将结构体的地址赋值给block。

分析得出

  1. __block_impl结构体中isa指针存储着&_NSConcreteStackBlock地址,可以暂时理解为其类对象地址,block就是_NSConcreteStackBlock类型的
  2. block代码块中的代码被封装成__main_block_func_0函数,FuncPtr则存储着__main_block_func_0函数的地址。
  3. Desc指向__main_block_desc_0结构体对象,其中存储__main_block_impl_0结构体所占用的内存。

问题总结:


此时已经基本对block的底层结构有了基本的认识,上述代码可以通过一张图展示其中各个结构体之间的关系。

image
本文有参考其他作者:
block文章---xxcc
上一篇 下一篇

猜你喜欢

热点阅读