XB_block(1)

1.block的本质

block本质上是一个OC对象,内部封装了函数调用和函数调用环境,底层结构如下图,第一位是__block_impl,第二位是__main_block_desc_0,后边是捕获的变量

其中__block_impl中存有一个FuncPtr的函数指针,block通过该指针调用了内部的函数。

注意:当调用函数的时候理论上应该是block-->impl.FuncPtr这样调用,但是由于impl是block的第一个成员,所以impl的地址就是block的地址,底层通过强制转换(struct __block_impl)block-->FuncPtr,直接用block调用函数。

__main_block_desc_0中的Block_size存有这个block的内存大小

2.block变量捕获

为了保证block内部能够正常访问外部的变量,比如auto变量的作用域和存储在栈区(变量释放时机)的因素让block有个变量捕获机制。

变量类型

捕获到block内部

访问方式

局部变量

auto

值传递

static

指针传递

全局变量

×

直接访问

 注意:auto局部变量与static局部变量访问方式不一样

struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
  int age;
  int *height;
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

 height是static局部变量,传入的是这个变量的地址,所以如果外部在调用block之前,捕获变量之后修改了static变量的值,block内部访问到的height是修改过的值。

3.block的类型

block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型,NSBlock的上一层是NSObject

1.__NSGlobalBlock__ ( _NSConcreteGlobalBlock )

2.__NSStackBlock__ ( _NSConcreteStackBlock )

3.__NSMallocBlock__ ( _NSConcreteMallocBlock )

 block类型的改变

block类型

环境

__NSGlobalBlock__

没有访问auto变量

__NSStackBlock__

访问了auto变量

__NSMallocBlock__

__NSStackBlock__调用了copy

注意:

如果block内部访问了类的属性或者self,都是访问了auto变量,比如

- (void)test
{
    void (^block)(void) = ^{
        NSLog(@"-------%d", [self name]);
        NSLog(@"-------%d", _name);
        NSLog(@"-------%d", self.name);
    };
    block();
}

这三种情况都是访问了auto变量,因为test方法底层是test(self,cmd)这样子的,其中一个默认参数就是self。如果第二条直接打印成员变量的情况,因为成员变量是属于self的,所以类似于self-->_name,所以图一中的block底层捕获的变量是对象类型的auto变量  NSObject *self(看类型了,也有可能是Person *self),而不是单独的name变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值