block实现

block内部结构

我们先写一个block

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void exampleBlock() {  
  2.     // NSConcreteStackBlock  
  3.     int a = 1;  
  4.     __block int b = 2;  
  5.     int(^blockTest0)(int c) = ^(int c){  
  6.         return a + b + c;  
  7.     };  
  8.     int c = 3;  
  9.     blockTest0(c);  
  10.   
  11.     // NSConcreteGlobalBlock  
  12.     void(^blockTest2)(void) = ^(void){  
  13.         ;  
  14.     };  
  15.     blockTest2();  
  16. }  

用clang转成c分析下

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. clang -rewrite-objc block.c  

可以看到他们的定义是

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. struct __exampleBlock_block_impl_0 {  
  2.   struct __block_impl impl;  
  3.   struct __exampleBlock_block_desc_0* Desc;  
  4.   int a;  
  5.   __Block_byref_b_0 *b; // by ref  
  6.   __exampleBlock_block_impl_0(voidvoid *fp, struct __exampleBlock_block_desc_0 *desc, int _a, __Block_byref_b_0 *_b, int flags=0) : a(_a), b(_b->__forwarding) {  
  7.     impl.isa = &_NSConcreteStackBlock;  
  8.     impl.Flags = flags;  
  9.     impl.FuncPtr = fp;  
  10.     Desc = desc;  
  11.   }  
  12. };  
  13.   
  14. // __block_impl  
  15. struct __block_impl {  
  16.   voidvoid *isa;  
  17.   int Flags;  
  18.   int Reserved;  
  19.   voidvoid *FuncPtr;  
  20. };  
  21.   
  22. // __exampleBlock_block_desc_0  
  23. struct __exampleBlock_block_impl_0 {  
  24.   struct __block_impl impl;  
  25.   struct __exampleBlock_block_desc_0* Desc;  
  26.   int a;  
  27.   __Block_byref_b_0 *b; // by ref  
  28.   __exampleBlock_block_impl_0(voidvoid *fp, struct __exampleBlock_block_desc_0 *desc, int _a, __Block_byref_b_0 *_b, int flags=0) : a(_a), b(_b->__forwarding) {  
  29.     impl.isa = &_NSConcreteStackBlock;  
  30.     impl.Flags = flags;  
  31.     impl.FuncPtr = fp;  
  32.     Desc = desc;  
  33.   }  
  34. };  
  35.   
  36. // __exampleBlock_block_impl_2  
  37. struct __exampleBlock_block_impl_2 {  
  38.   struct __block_impl impl;  
  39.   struct __exampleBlock_block_desc_2* Desc;  
  40.   __exampleBlock_block_impl_2(voidvoid *fp, struct __exampleBlock_block_desc_2 *desc, int flags=0) {  
  41.     impl.isa = &_NSConcreteStackBlock;  
  42.     impl.Flags = flags;  
  43.     impl.FuncPtr = fp;  
  44.     Desc = desc;  
  45.   }  
  46. };  

初始化和执行代码

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void exampleBlock() {  
  2.     // blockTest0  
  3.     int a = 1;  
  4.     __attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0sizeof(__Block_byref_b_0), 2};  
  5.   
  6.     int(*blockTest0)(int c) = (int (*)(int))&__exampleBlock_block_impl_0((voidvoid *)__exampleBlock_block_func_0, &__exampleBlock_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344);  
  7.   
  8.     int c = 3;  
  9.     ((int (*)(__block_impl *, int))((__block_impl *)blockTest0)->FuncPtr)((__block_impl *)blockTest0, c);  
  10.   
  11.     // blockTest2  
  12.     void(*blockTest2)(void) = (void (*)())&__exampleBlock_block_impl_2((voidvoid *)__exampleBlock_block_func_2, &__exampleBlock_block_desc_2_DATA);  
  13.     ((void (*)(__block_impl *))((__block_impl *)blockTest2)->FuncPtr)((__block_impl *)blockTest2);  
  14. }  

我们先看看blockTest2,它是由 结构体impl, 结构体Desc, 构造方法__exampleBlock_block_impl_2() 组成展开后是

  • *isa 指向该实例对象(代码里是NSConcreteStackBlock,其实应该是NSConcreteGlobalBlock)
  • Flags 用于按bit位表示一些block的附加信息
  • reserved 保留变量
  • *FuncPtr 函数指针,指向具体的block实现的函数调用地址(代码里是__exampleBlock_block_func_2)
[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static void __exampleBlock_block_func_2(struct __exampleBlock_block_impl_2 *__cself) {  
  2.         ;  
  3. }  
  • size_t reserved 这个传进来的是0
  • Block_size 结构体的大小
[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static struct __exampleBlock_block_desc_2 {  
  2.   size_t reserved;  
  3.   size_t Block_size;  
  4. } __exampleBlock_block_desc_2_DATA = { 0sizeof(struct __exampleBlock_block_impl_2)};  

然后我们在看blockTest,它比blockTest2多了2个变量a, b

  • int a; 外部变量a,

  • Block_byref_b_0 *b; 加了block修饰的b, 传的是 Block_byref_b_0

在生成的初始化代码中则多了3个传入值

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int(*blockTest0)(int c) = (int (*)(int))&__exampleBlock_block_impl_0((voidvoid *)__exampleBlock_block_func_0, &__exampleBlock_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344);  
  • a是这个是直接传值进去,然后被复制给 a

  • b是传的地址, 是把 __Block_byref_b_0 赋值给 b

__Block_byref_b_0这个结构体是

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. struct __Block_byref_b_0 {  
  2.   voidvoid *__isa;  
  3. __Block_byref_b_0 *__forwarding;  
  4.  int __flags;  
  5.  int __size;  
  6.  int b;  
  7. };  

__forwarding 是一个指向自己的指针.

__Block_byref_b_0 的初始化代码如下:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. __attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0sizeof(__Block_byref_b_0), 2};  

我们可以看出a是直接复制进去的,b是被转到了一个结构体里,然后吧这个结构体的指针传进去,所以block不能修改a,能修改b.

  • 570425344 这个应该是传给Flags

blockTest0的Desc和blockTest2也有所不同,展开后是

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static struct __exampleBlock_block_desc_0 {  
  2.   size_t reserved;  
  3.   size_t Block_size;  
  4.   void (*copy)(struct __exampleBlock_block_impl_0*, struct __exampleBlock_block_impl_0*);  
  5.   void (*dispose)(struct __exampleBlock_block_impl_0*);  
  6. } __exampleBlock_block_desc_0_DATA = { 0sizeof(struct __exampleBlock_block_impl_0), __exampleBlock_block_copy_0, __exampleBlock_block_dispose_0};  

多了2个函数指针copy, dispose,对于在调用前后修改相应变量的引用计数, 分别指向

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static void __exampleBlock_block_copy_0(struct __exampleBlock_block_impl_0*dst, struct __exampleBlock_block_impl_0*src) {_Block_object_assign((void*)&dst->b, (void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/);}  
  2.   
  3. static void __exampleBlock_block_dispose_0(struct __exampleBlock_block_impl_0*src) {_Block_object_dispose((void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/);}  

再来看下blockTest0的*FuncPtr

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int __exampleBlock_block_func_0(struct __exampleBlock_block_impl_0 *__cself, int c) {  
  2.  __Block_byref_b_0 *b = __cself->b; // bound by ref  
  3.  int a = __cself->a; // bound by copy  
  4.   
  5.        return a + (b->__forwarding->b) + c;  
  6.    }  

可以看出a用的是拷贝进来的a, b用的是结构体里的b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值