前言
最近在总结关于block的东西,可能会写几篇关于block的博客,语法那些就不说,这里提供一个语法的入口,我们主要探究block的底层实现、block引用局部变量、block的内存管理,今天先讲下block的底层实现。
block实例
#import <Foundation/Foundation.h>
void hello_(){
int i = 2;
int j = 3;
long (^myBlock)(void) = ^long(){
return i*j*10;
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
}
return 0;
}
定义hello方法是方便我们等下查看编译代码的时候准确定位myBlock的实现。用clang将objected-C 代码编译为C++代码。
控制台命令:clang -rewrite-objc main.m
我们打开main.cpp文件,定位到以下代码:
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
这是block基类的定义,所有block都继承于它,拥有它以下那些属性:
isa是指向该block的类型的类,也就是我们理解的对象指针;
Flags包含了引用计数;
Reserved:保留变量,我的理解是表示block内部的变量数;
FuncPtr:函数指针,指向具体block实现的函数的调用地址;
struct __hello__block_impl_0 {
struct __block_impl impl;
struct __hello__block_desc_0* Desc;
int i;
int j;
__hello__block_impl_0(void *fp, struct __hello__block_desc_0 *desc, int _i, int _j, int flags=0) : i(_i), j(_j) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
这是myBlock的定义,它的结构体以hello打头,代表myBlock位于hello函数里,这是block的命名方式。__hello__block_desc_0指的是myBlock的描述。
static long __hello__block_func_0(struct __hello__block_impl_0 *__cself) {
int i = __cself->i; // bound by copy
int j = __cself->j; // bound by copy
return i*j*10;
}
myBlock内函数的具体实现,注意bound by copy,block对外部引用变量做只读拷贝,还有另外的一种情况,在以后讲到关于block引用局部变量的时候会说。
static struct __hello__block_desc_0 {
size_t reserved;
size_t Block_size;
} __hello__block_desc_0_DATA = { 0, sizeof(struct __hello__block_impl_0)};
这是myBlock的具体描述
void hello_(){
int i = 2;
int j = 3;
long (*myBlock)(void) = ((long (*)())&__hello__block_impl_0((void *)__hello__block_func_0, &__hello__block_desc_0_DATA, i, j));
}
myBlock实例变量的定义
做下小小总结
block是对象;
编译器会根据block捕获的局部变量,生成具体的结构体定义。block内部的代码将会提取出来,成为一个单独的C函数(eg:__hello__block_func_0)。创建block时,实际就是在方法中声明一个struct,并且初始化该struct的成员。而执行block时,就是调用那个单独的C函数,并把该struct指针传递过去;
block中包含了被引用的局部变量(由struct持有),也包含了控制成分的代码块(由函数指针持有),符合闭包(closure)的概念。
网友评论