item在c语言程序设计,《Objective-C高级编程》Blocks 阅读笔记 item2(Block的实质)...

《Objective-C高级编程》Blocks 阅读笔记系列

2.3 Blocks的实现

2.3.1 Block的实质

Clang(LLVM编译器)具有将含有Block语法的源代码转换为我们可读源代码的功能。通过“-rewrite-objc”选项就能将含有Block语法的源代码变换为C++的源代码(本质是使用了struct结构的C语言源代码)。

int main()

{

void (^blk)(void) = ^{printf("Block\n");};

blk();

return 0;

}

通过clang转换为以下形式:

// 结构体 __block_impl

struct __block_impl {

void *isa;

int Flags; // 标志

int Reserved; // 今后版本升级所需的区域

void *FuncPtr; // 函数指针

};

// 结构体 __main_block_impl_0

struct __main_block_impl_0 {

// 成员变量

struct __block_impl impl;

struct __main_block_desc_0* Desc;

// 该结构体的构造函数

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags = 0){

// _NSConcreteStackBlock用于初始化__block_impl结构体的isa成员

// (将Block指针赋值给Block的结构体成员变量isa)

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

// 最初的源代码中的Block语法经clang变换,被处理成简单的C语言函数(该函数以Block语法所属的函数名——main和该Block语法在该函数出现的顺序值——0来命名)。

// __ceself为指向Block值的变量。

static void __main_block_func_0(struct __main_block_impl_0 *__cself)

{

printf("Block\n");

}

// 静态结构体 __main_block_desc_0

static struct __main_block_desc_0{

unsigned long reserved; // 今后版本升级所需的区域

unsigned long Block_size; // Block的大小

} __mian_block_desc_0_DATA = { // 该结构体实例的初始化部分

0,

sizeof(struct __main_block_impl_0) // 使用Block(即__main_block_impl_0结构体实例)的大小进行初始化

};

// main函数,从这里开始阅读源代码

int main()

{

// 调用结构体__main_block_impl_0的构造函数__main_block_impl_0

void (*blk)(void) =

(void (*)(void)) & __main_block_impl_0(

(void *)__main_block_func_0, &__mian_block_desc_0_DATA);

/*

去掉转换部分,如下:

struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);

struct __main_block_impl_0 *blk = &tmp;

这段代码对应:

void (^blk)(void) = ^{printf("Block\n");};

理解:

1. 将__main_block_impl_0结构体类型的自动变量(即栈上生成的__main_block_impl_0结构体实例的指针)赋值给__main_block_impl_0结构体指针类型的变量blk

2. __main_block_func_0是由Block语法转换的C语言函数指针。

3. __main_block_desc_0_DATA作为静态全局变量初始化的__main_block_desc_0结构体实例指针

4. 将__main_block_impl_0的__block_impl进行展开,__main_block_impl_0结构体根据构造函数会像下面进行初始化:

isa = &_NSConcreteStackBlock;

Flags = 0;

Reserved = 0;

FuncPtr = __main_block_func_0;

Desc = &__main_block_desc_0_DATA;

*/

((void (*)(struct __block_impl *))(

(struct __block_impl *)blk)->FuncPtr) ((struct __block_impl *)blk);

/*

去掉转换部分,如下:

(*blk->impl.FuncPtr)(blk);

这段代码对应:

blk();

理解:

1. 使用函数指针调用函数

2. 由Block语法转换的__main_block_func_0函数的指针被赋值成员变量FuncPtr中

3. __main_block_func_0函数的参数__cself指向Block值,在调用该函数的源代码中可以看出Block正是作为参数进行了传递

*/

return 0;

}

Block就是Objective-C对象

在弄清楚Block就是Objective-C对象前,要先理解objc_object结构体和objc_class结构体。

id类型是objc_object结构体的指针类型。

typedef struct objc_object {

Class isa;

} *id;

Class是objc_class结构体的指针类型。

typedef struct objc_class *Class;

struct objc_class {

Class isa;

} ;

objc_object结构体和objc_class结构体归根到底是各个对象和类的实现中最基本的结构体。

*** 如下,通过一个简单的MyObject类来说明Objective-C类与对象的实质:***

@interface MyObject : NSObject

{

int val0;

int val1;

}

*** 基于objc_object结构体,该类的对象的结构体如下:***

struct MyObject {

Class isa; // 成员变量isa持有该类的结构体实例指针

int val0; // 原先MyObject类的实例变量val0和val1被直接声明为成员变量

int val1;

}

理解:

MyObject类的实例变量val0和val1被直接声明为对象的成员变量。

“Objective-C中由类生成对象”意味着,像该结构体这样“生成由该类生成的对象的结构体实例”。

生成的各个对象(即由该类生成的对象的各个结构体实例),通过成员变量isa保持该类的结构体实例指针。

dfdb1b379ea2

Snip20160215_13.png

*** 各类的结构体是基于objc_class结构体的class_t结构体:***

struct class_t {

struct class_t *isa;

struct class_t *superclass;

Cache cache;

IMP *vtable;

uintptr_t data_NEVER_USE;

}

理解:

在Objective-C中,比如NSObject的class_t结构体实例以及NSMutableArray的class_t结构体实例等,均生成并保持各个类的class_t结构体实例。

该实例持有声明的成员变量、方法的名称、方法的实现(即函数指针)、属性以及父类的指针,并被Objective-C运行时库所使用。

回到正题——“Block就是Objective-C对象”,*** 先看Block结构体:***

struct __main_block_impl_0 {

void *isa;

int Flags; // 标志

int Reserved; // 今后版本升级所需的区域

void *FuncPtr; // 函数指针

struct __main_block_desc_0* Desc;

};

理解:

此__main_block_impl_0结构体相当于基于objc_object结构体的Objective-C类的对象的结构体。

对其中的isa进行初始化,如

isa = &_NSConcreteStackBlock;

即_NSConcreteStackBlock相当于class_t结构体实例

在将Block作为Objective-C的对象处理时,关于该类的信息放置于_NSConcreteStackBlock中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值