《Objective-C|《Objective-C 高级编程》第二篇(Block源代码解析)
本系列文章主要是对《Objective-C 高级编程》这本书做的读书笔记总结,除了这本书中的内容以外,也加上了自己对开发技术的理解和一些个人的经验分享。
Objective-C源代码 转 C++源代码的的方法
通过 clang(LLVM编译器)命令转换:
clang -rewrite-objc 源代码的文件名
先来看一个最简单的block
int main() {void (^blk)(void) = ^{
printf("我是block\n");
};
blk();
return 0;
}
将以上源代码转换成C++源代码
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
//block结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
//Block构造函数
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
// 将来被调用的block内部的代码:block值被转换为C的函数代码
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {printf("我是block\n");
}static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = https://www.it610.com/article/{ 0, sizeof(struct __main_block_impl_0)};
//main 函数
int main() {void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
return 0;
}
看下面的代码
^ {
printf("我是block\n");
};
可以看到,变换后的源代码中也含有相同的表达式
static void __main_block_func_0(struct __main_block_impl_0 * __cself) {printf("我是block\n");
}
通过block使用的匿名函数实际上被作为简单的C语言函数来处理。根据block语法所属的函数名(此处为main)和该block语法在该函数出现的顺序值(此处为0)来给函数命名 __main_block_func_0
该函数的参数 __cself 相当于C++实例方法中指向实例自身的变量this,或是Object-C实例方法中指向对象自身的变量self,即参数 __cself 为指向block值的变量。
这里的 __main_block_func_0 函数并没有使用到 __cself。使用 __cself 的例子将在后面介绍,我们先来看看该参数的声明,参数 __cself 是 __main_block_func_0 结构体的指针。
struct __main_block_impl_0 * __cself
该结构体的声明如下:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0 * Desc;
}
第一个成员变量是 impl,我们先来看一下 __block_impl 结构体的声明。
struct __block_impl {
void *isa;
int Flags;
// 标志
int Reserved;
void *FuncPtr;
}
接下来我们看一下第二个成员变量 Desc指针
struct __main_block_desc_0 {
unsigned long reserved;
// 版本升级所需的区域
unsigned long Block_size;
// block的大小
}
那么,我们再来看一下初始化这些结构体的 _main_block_impl_0 结构体的构造函数
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
NSConcreteStackBlock用于初始化 __block_impl结构体 的isa成员,后面将会讲解。我们先来看一下该构造函数的调用。
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
因为转换较多,所以看起来比较不清楚,我们来去掉转换的部分,再看一下
struct __main_block_impl_0 temp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
struct __main_block_impl_0 *blk = &temp;
这样就容易理解了。该源代码将 __main_block_impl_0结构体 类型的自动变量,赋值给 __main_block_impl_0结构体指针类型的变量blk
【《Objective-C|《Objective-C 高级编程》第二篇(Block源代码解析)】下面就来看看 __main_block_impl_0结构体实例构造参数。
__main_block_impl_0 (__main_block_func_0, &__main_block_desc_0_DATA);
第一个参数是由block语法转换为C语言函数指针。第二个参数是作为静态全局变量初始化的 __main_block_desc_0 结构体的实例指针。
以下为 __main_block_desc_0 结构体实例的初始化部分代码,可以看到源代码使用 __main_block_impl_0 结构体的实例大小,进行初始化。
static struct __main_block_desc_0 __main_block_desc_0_DATA = https://www.it610.com/article/{
0,
sizeof(struct __main_block_impl_0)
};
下面看看栈上的 __main_block_impl_0结构体 实例是如何根本这些参数进行初始化的。
struct __main_block_impl_0 {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
struct __main_block_desc_0* Desc;
};
该结构体根据构造函数会像下面这样进行初始化
isa = &_NSConcreteStackBlock;
Flags = 0;
Reserved = 0;
FuncPtr = __main_block_func_0;
Desc = &__main_block_desc_0_DATA;
将 __main_block_func_0 函数指针赋给成员变量 FuncPtr
blk();
转换后的源代码如下
((void (*)(struct __block_impl *))((struct __block_impl *)blk)->FuncPtr)((struct __block_impl *)blk);
去掉转换部分:
(*blk -> impl.FuncPtr)(blk);
这就是简单地使用函数指针调用函数。
推荐阅读
- 慢慢的美丽
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 《跨界歌手》:亲情永远比爱情更有泪点
- 诗歌:|诗歌: 《让我们举起世界杯,干了!》
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- 人间词话的智慧
- 《一代诗人》37期,生活,江南j,拨动心潭的一泓秋水
- 广角叙述|广角叙述 展众生群像——试析鲁迅《示众》的展示艺术
- 书评——《小行星》