从声明定义到底层原理,搞懂block的全部内容系列文章(二)block在c层面的数据结构

二 block的底层数据结构

block被称为封装了函数及函数调用环境的OC对象,如何理解这个概念呢?说一千道一万,不如看一眼底层实现,我们新建一个macos command line工程,定义一个简单的block,然后用编译器将其main.m翻译为c++:

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
int main(int argc, const char * argv[]) {
    @autoreleasepool {
	    int a = 10;
        int (^blockname)(int,NSString *) = ^(int b,NSString *name) {
            NSLog(@"%d",a);
            return b+name.length;
        };
        blockname(20,@"qwe");
    }
}
上述main翻译后为:
int main(){
	int a = 10;
	blockname = __main_block_impl(__main_block_func_0,desc_data,a);
	blockname->FuncPtr(blockname,20,@"qwe");
}

和block有关的关键C结构如下:

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
}
static __main_block_func_0(struct __main_block_impl*cself,int b,NSString *name){
	NSLog(@"%d",cself->a);
	return b+name.length;
}
struct __main_block_impl {
	struct __block_impl impl;
	struct __main_block_desc_0 *desc;
	int a;
	__main_block_impl(void *funcptr,struct __main_block_desc_0 *descDATA,int _a){
		impl.isa = &_NSConcreteStackBlock;
		impl.FuncPtr = funcptr;
		desc = descDATA;
		a = _a;
	}
}
  • 由上可知,blockname的创建,其实就是创建了一个struct __main_block_impl类型的结构体变量,且结构体成员变量中有isa指针,故称block为oc对象(因为一般认为isa指针是oc对象的标志)。
  • 再仔细观察struct __main_block_impl的构造函数及结构体内部的成员变量void *FuncPtr、int a,构造函数在创建blockname对象的时候,会传入funcptr和_a并由上述成员变量存储起来,而构造函数的入参funcptr和_a,分别是一个外部函数__main_block_func_0和外部局部变量int a,而外部函数__main_block_func_0的实现正是blockname的代码体,int a正是代码体用到的外部局部变量。所以,block对象内部封装了block的代码体以及代码体引用的外部变量,故称block封装了函数及函数调用环境
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值