探索IOS block,究竟是什么原理

OC开发中,Block的使用随处可见,并且功能还是蛮强大的,很多开发入门者觉得block太神秘,不太好理解,接下来就从底层源代码去分析block究竟是什么东西,看完本文之后我相信你们会觉得block原来这么简单!

怎么探究呢?首先我们在main方法中加入一行简单的block语句:

  1. int main(int argc, const char * argv[]) {
  2.     void (^block)() = ^ {
  3.         printf("Hello NingCool.com");
  4.     };
  5.     block();
  6.     return 0;
  7. }

然后我们编译这个简单的main函数文件,使用CLang指令:

clang -rewrite-objc main.m

得到如下结构,其实block就是这两个结构。

  1. struct Block_descriptor {
  2.     unsigned long int reserved;
  3.     unsigned long int size;
  4.     void (*copy)(void *dst, void *src);
  5.     void (*dispose)(void *);
  6. };
  7. struct Block_layout {
  8.     void *isa;
  9.     int flags;
  10.     int reserved;
  11.     void (*invoke)(void *, ...);
  12.     struct Block_descriptor *descriptor;
  13.     /* Imported variables. */
  14. };

来,我们看看具体生成了什么:
探索IOS block,究竟是什么原理

你定义的block,其实是创建了一个函数,在创建block结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。

再看看值捕获的问题
探索IOS block,究竟是什么原理
探索IOS block,究竟是什么原理

定义block的时候,变量a的值就传递到了block结构体中,仅仅是值传递,所以在block中修改a是不会影响到外面的a变量的。

再看看增加__block前缀的情况:我们会发现在main函数中调用初始化block结构体的时候,是传递了变量a的指针。这个时候我们是不是恍然大悟,原来是这样子的。
探索IOS block,究竟是什么原理
探索IOS block,究竟是什么原理

把a的地址传过去了,所以在block内部便可以修改到外面的变量了。

拓展阅读:根据isa指针,block一共有3种类型的block

_NSConcreteGlobalBlock 全局静态

_NSConcreteStackBlock 保存在栈中,出函数作用域就销毁。

_NSConcreteMallocBlock 保存在堆中,retainCount == 0销毁。(copy,赋值给strong修饰的id变量的对象,或者赋值给block类型的成员变量都会导致栈区的block到堆区)

而ARC和MRC中,block还略有不同:请看这篇文章:ARC与MRC下,Block的不同之处。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: