标签:
2.3 Blocks的实现
2.3.1 Block的实质
通过命令”clang -rewrite-objc 文件名”能够将含有Block语法的源代码转换为C++源代码。
含有Block的源代码如下:
#include
<stdio.h>//不导入库文件无法运行
int
main() {
void(^testBlock)(void)=^{
printf("i am testBlock");
};
testBlock();
}
转换后的代码有五百行左右,这里只选择我们关心的部分:
struct
__block_impl {
void
*isa;
int
Flags;
int
Reserved;
void
*FuncPtr;
};
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) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static
void
__main_block_func_0(struct
__main_block_impl_0 *__cself) {
printf("i am testBlock");
}
static
struct
__main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = {
0,
sizeof(struct
__main_block_impl_0)};
int
main() {
void(*testBlock)(void)=(void
(*)())&__main_block_impl_0((void
*)__main_block_func_0, &__main_block_desc_0_DATA);
((void
(*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);
}
通过Blocks使用的匿名函数被作为简单的C语言函数来处理:
static
void
__main_block_func_0(struct
__main_block_impl_0 *__cself) {
printf("i am testBlock");
}
该函数的参数”__cself”相当于C++实例方法中指向实例真身的变量this,也相当于OC示例方法中指向自身的变量”self”,即参数”__cself”为指向Block值的变量。
__cself是__main_block_impl_0类型的结构体指针,该结构体的定义是(不包括构造函数):
struct
__main_block_impl_0 {
struct
__block_impl impl;
struct
__main_block_desc_0* Desc;
}
可以看到,__main_block_impl_0共有两个变量,第一个是__block_impl类型的“impl”,定义如下
struct
__block_impl {
void
*isa;
int
Flags;
int
Reserved;
void
*FuncPtr;
};
第二个是__main_block_desc_0类型的”Desc",定义如下:
static
struct
__main_block_desc_0 {
size_t reserved;
size_t Block_size;
}
回头看一下__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;
}
构造函数的调用是如下语句:
void(*testBlock)(void)=(void
(*)())&__main_block_impl_0((void
*)__main_block_func_0, &__main_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 *testBlock=&tmp;
其中调用构造函数时有两个参数,第一个是由Block语法转换的C语言函数指针,第二个作为静态全局变量初始化的__main_block_desc_0结构体实例指针,初始化代码如下:
__main_block_desc_0_DATA = {
0,
sizeof(struct
__main_block_impl_0)};
可知该源码使用__main_desc_impl_0结构体实例的大小进行初始化。
下面看一下__main_desc_impl_0初始化的过程,展开__block_impl,其结构体与初始化对比如下:
结构体:
struct
__main_block_impl_0 {
//__block_impl
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;
|
使用Block的源码为:testBlock();
转换后的源码为:
((void
(*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);
去掉转换部分之后:
(*testBlock->impl.FuncPtr)(testBlock);
这是使用函数指针调用函数。之前__main_block_func_0赋值给FuncPtr,而参数(__cself)就是指向Block的值。
文字的解释不够直观,可看图理解。
接下来解释一下 isa = &_NSConcreteStackBlock;这句话。
将Block指针赋值给Block结构体成员变量isa。为了理解这句话,先要理解OC中类与对象的实质,下面是解释类与对象的关系.
Block是OC对象,“id”用来存储OC对象,id类型也能够在c语言中声明:
typedef struct objc_object{
Class isa;
} *id;
id 为objc_object结构体指针类型。Class的定义如下:
typedef struct objc_class*Class;
Class为objc_class结构体的指针类型,objc_class结构体在模拟器目录下/usr/include/objc/runtime.h(导入
#import
<objc/runtime.h>点击可进入)中声明如下(除去无关宏定义):
struct
objc_class {
Class isa;
};
objc_class与结构体objc_object的定义相同。但是分别是在类与对象中使用的结构体,下面通过简单的OC类声明来验证一下。
@interface
MyObject : NSObject
{
int
val0;
int
val1;
}
@end
基于objc_object结构体,该类的对象的结构体如下:
struct
MyObject{
Class isa;
int
val0;
int
val1;
};
类中的实例变量被包含在对象的结构体中,类生成对象意味着类生成该类的对象的各个结构体实例,通过成员变量isa保持该类的结构体实例指针(即isa为指向所属类的结构体实例的指针),如下图:
各类的结构体就是基于objc_class结构体的class_t结构体,class_t结构体在objc4运行时库的声明如下:
struct
class_t{
struct
class_t *isa;
struct
class_t *superclass;
Cache cache;
IMP
*vtable;
uintptr_t data_NEVER_USE;
};
在OC中,各个类的结构体实例均生成并保持各个类的class_t结构体实例。该实例存有类的相关信息,包括持有声明的成员变量、方法的名称、方法的实现(函数指针)、属性即父类的指针,并被OC运行时库所使用。
|
回到刚才的代码,_NSConcreteStackBlock相当于class_t的结构体实例,将Block作为OC对象处理,关于该类的信息放置于_NSConcreteStackBlock中。所以说Block是OC对象。
[读书笔记]iOS与OS X多线程和内存管理 [Blocks部分-2]
标签:
原文地址:http://blog.csdn.net/zhaoyabei/article/details/44055939