Block 原理浅析
Block 浅析
一、Block内存
(堆、栈、全局)
- 知识点:
-
栈
区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。 -
堆
区(malloc) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。 -
全局
区(静态区)(global)—,全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放。
Block定义:
Block
就是
一个里面存储
了指向定义block时的代码块的函数指针
,以及block外部上下文变量信息的结构体
。
OC 中有三种常见的Block:全局区、栈区、堆区。
- 全局Block
没有访问外部局部变量(基本数据、OC对象)、成员属性变量 或 只访问全局变量、静态变量(全局静态或局部静态)
//全局静态变量
int static globalStaticInt = 100; //全局变量
//全局变量
int globalInt = 100;
- (void)globalBlock{
//全局Block
//局部静态变量
int static tempStaticInt = 10;
void(^testBlock)(int a) = ^(int a){
NSLog(@"%d",tempStaticInt);
};
//runtime 获取block的类
Class blockClass = object_getClass(testBlock);
NSLog(@"testBlock :%@",blockClass);
//runtime 获取类的父类
Class superClass = class_getSuperclass(blockClass);
while (superClass) {
NSLog(@"superClass:%@",superClass);
superClass = class_getSuperclass(superClass);
}
testBlock(4);
}
Block的继承关系:__NSGlobalBlock__ -----> NSBlock -----> NSObject
- 栈区Block
- MRC:用到了外部局部变量(基本数据、OC对象)、成员属性变量,且没有强引用Block。// 文件添加 -fno-objc-arc 标记变为MRC编译。
- MRC:用到了外部局部变量(基本数据、OC对象)、成员属性变量,且Block用weak修饰。
//局部变量
int temInt = 100;
UILabel *templabel = [UILabel new];
//成员变量
memberLabel = [UILabel new];
//属性
self.propertyLabel = [UILabel new];
void(^tempBlock)(int a) = ^(int a){
NSLog(@"%d",temInt);
NSLog(@"%@",templabel);
NSLog(@"%@",memberLabel);
NSLog(@"%@",self.propertyLabel);
};
Class blockClass = object_getClass(tempBlock);
NSLog(@"testBlock :%@",blockClass);
Class superClass = class_getSuperclass(blockClass);
while (superClass) {
NSLog(@"superClass:%@",superClass);
superClass = class_getSuperclass(superClass);
}
tempBlock(4);
Block的继承关系:__NSStackBlock__ -----> NSBlock -----> NSObject
- 堆区Block
- 用到了外部局部变量(基本数据、OC对象)、成员属性变量,且有强引用Block。
- ARC: 用到了外部局部变量(基本数据、OC对象)、成员属性变量,且没有强引用Block,创建之初是栈区Block,创建后会执行_Block_copy函数,将栈区Block复制在堆区。
int tempInt = 100;
self.strongBlock = ^{
// NSLog(@"%@",self.propertyLabel);
NSLog(@"%d",globalStaticInt);
NSLog(@"%d",tempInt);
};
self.copyBlock = ^{
// NSLog(@"%@",self.propertyLabel);
NSLog(@"%d",globalStaticInt);
NSLog(@"%d",tempInt);
};
self.weakBlock = ^{
// NSLog(@"%@",self.propertyLabel);
NSLog(@"%d",globalStaticInt);
NSLog(@"%d",tempInt);
};
Class strongBlockClass = object_getClass(self.strongBlock);
Class copyBlockClass = object_getClass(self.copyBlock);
Class weakBlockClass = object_getClass(self.weakBlock);
NSLog(@"strongBlockClass:%@ *** copyBlockClass:%@ *** weakBlockClass:%@",strongBlockClass,copyBlockClass,weakBlockClass);
Block(strong,copy)的继承关系:__NSMallocBlock__ -----> NSBlock -----> NSObject
-
灵魂拷问:block在内存中的哪个区与block有没有参数是否有关系呢?如果有,那个于参数种类又有没有关系呢?
二、Block结构
(oc的Block编译后长什么样子?)
- 首先来看几个block例子:
- 截获局部变量的Block
int age = 10;
void (^block)(void) = ^() {
NSLog(@"age = %d,",age);
};
age = 20;
block();
- 截获静态局部变量的Block
int static age = 10;
void (^block)(void) = ^() {
NSLog(@"age = %d,",age);
};
age = 20;
block();
- 截获全局变量的Block
int static age = 10;
void (^block)(void) = ^() {
NSLog(@"age = %d,",age);
};
age = 20;
block();
-
上面三个block执行后最终输出的age的值是啥呢?为什么会这样?
- Block转为C++
显示SDK版本:xcodebuild -showsdks
转成C++:
xcrun -sdk iphonesimulator14.5 clang -S -rewrite-objc -fobjc-arc -fobjc-runtime=ios-14.5 VC.m
block的基础信息的结构体(所有的Block都是以此为结构为模板)
struct __block_impl {
void *isa; //无类型指针
int Flags; //标志
int Reserved; //保留值
void *FuncPtr; //函数指针
};
- 2.1空Block
//初始化
void(^voidBlock) (void) = ^ {
NSLog(@"空Block");
};
voidBlock(); //执行
转成C++代码
//voidBlock 对应的结构体
struct __VC__voidBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__voidBlock_block_desc_0* Desc; //描述信息
//构造函数
__VC__voidBlock_block_impl_0(void *fp, struct __VC__voidBlock_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags; //flags标记
impl.FuncPtr = fp; //block块内执行的代码的函数指针
Desc = desc; //描述信息
}
};
//block块内执行的代码的函数
static void __VC__voidBlock_block_func_0(struct __VC__voidBlock_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_0);
}
//描述信息
static struct __VC__voidBlock_block_desc_0 {
size_t reserved; //保留位
size_t Block_size; //block的大小
} __VC__voidBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__voidBlock_block_impl_0)}; //实例化
//voidBlock 初始化
void(*voidBlock) (void) = ((void (*)())&__VC__voidBlock_block_impl_0((void *)__VC__voidBlock_block_func_0, &__VC__voidBlock_block_desc_0_DATA));
//获取voidBlock对应的结构体的FuncPtr函数指针,并执行。voidBlock();
((void (*)(__block_impl *))((__block_impl *)voidBlock)->FuncPtr)((__block_impl *)voidBlock);
}
- 2.2临时变量Block,定义结构体时候添加了对应的变量
int tempInt = 100;
//初始化
void(^simpleDateBlock) (void) = ^ {
NSLog(@"简单实数Block -- %d",tempInt);
};
simpleDateBlock(); //执行
转C++
struct __VC__simpleDateBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__simpleDateBlock_block_desc_0* Desc;
int tempInt;
__VC__simpleDateBlock_block_impl_0(void *fp, struct __VC__simpleDateBlock_block_desc_0 *desc, int _tempInt, int flags=0) : tempInt(_tempInt) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__simpleDateBlock_block_func_0(struct __VC__simpleDateBlock_block_impl_0 *__cself) {
int tempInt = __cself->tempInt; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_1,tempInt);
}
static struct __VC__simpleDateBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __VC__simpleDateBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__simpleDateBlock_block_impl_0)};
- 2.3包含临时的objc对象的block:定义结构体时候添加了对应__strong类型的变量
UILabel *lab = [UILabel new];
void(^tempObjDateBlock) (void) = ^ {
NSLog(@"简单实数Block -- %@",lab);
};
tempObjDateBlock();
转C++
struct __VC__tempObjDateBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__tempObjDateBlock_block_desc_0* Desc;
UILabel *__strong lab;
__VC__tempObjDateBlock_block_impl_0(void *fp, struct __VC__tempObjDateBlock_block_desc_0 *desc, UILabel *__strong _lab, int flags=0) : lab(_lab) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__tempObjDateBlock_block_func_0(struct __VC__tempObjDateBlock_block_impl_0 *__cself) {
UILabel *__strong lab = __cself->lab; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_2,lab);
}
static void __VC__tempObjDateBlock_block_copy_0(struct __VC__tempObjDateBlock_block_impl_0*dst, struct __VC__tempObjDateBlock_block_impl_0*src) {_Block_object_assign((void*)&dst->lab, (void*)src->lab, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __VC__tempObjDateBlock_block_dispose_0(struct __VC__tempObjDateBlock_block_impl_0*src) {_Block_object_dispose((void*)src->lab, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __VC__tempObjDateBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __VC__tempObjDateBlock_block_impl_0*, struct __VC__tempObjDateBlock_block_impl_0*);
void (*dispose)(struct __VC__tempObjDateBlock_block_impl_0*);
} __VC__tempObjDateBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__tempObjDateBlock_block_impl_0), __VC__tempObjDateBlock_block_copy_0, __VC__tempObjDateBlock_block_dispose_0};
- 2.4成员变量(objc)的block:强引入是VC对应的self,通过self.label获取值
_label = [UILabel new];
void(^tempMemObjDateBlock) (void) = ^ {
NSLog(@"简单实数Block -- %@",_label);
};
tempMemObjDateBlock();
转C++
struct __VC__tempMemObjDateBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__tempMemObjDateBlock_block_desc_0* Desc;
VC *const __strong self;
__VC__tempMemObjDateBlock_block_impl_0(void *fp, struct __VC__tempMemObjDateBlock_block_desc_0 *desc, VC *const __strong _self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__tempMemObjDateBlock_block_func_0(struct __VC__tempMemObjDateBlock_block_impl_0 *__cself) {
VC *const __strong self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_3,(*(UILabel *__strong *)((char *)self + OBJC_IVAR_$_VC$_label)));
}
static void __VC__tempMemObjDateBlock_block_copy_0(struct __VC__tempMemObjDateBlock_block_impl_0*dst, struct __VC__tempMemObjDateBlock_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __VC__tempMemObjDateBlock_block_dispose_0(struct __VC__tempMemObjDateBlock_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __VC__tempMemObjDateBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __VC__tempMemObjDateBlock_block_impl_0*, struct __VC__tempMemObjDateBlock_block_impl_0*);
void (*dispose)(struct __VC__tempMemObjDateBlock_block_impl_0*);
} __VC__tempMemObjDateBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__tempMemObjDateBlock_block_impl_0), __VC__tempMemObjDateBlock_block_copy_0, __VC__tempMemObjDateBlock_block_dispose_0};
//初始化
(*(UILabel *__strong *)((char *)self + OBJC_IVAR_$_VC$_label)) = ((UILabel *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("UILabel"), sel_registerName("new"));
//初始化
void(*tempMemObjDateBlock) (void) = ((void (*)())&__VC__tempMemObjDateBlock_block_impl_0((void *)__VC__tempMemObjDateBlock_block_func_0, &__VC__tempMemObjDateBlock_block_desc_0_DATA, self, 570425344));
//执行
((void (*)(__block_impl *))((__block_impl *)tempMemObjDateBlock)->FuncPtr)((__block_impl *)tempMemObjDateBlock);
- 2.5全局变量global value:未添加变量,而是直接使用全局区globalV
int globalV = 100;
- (void)globalValueBlock {
void(^globalValueBlock) (void) = ^ {
NSLog(@"简单实数Block -- %d",globalV);
};
globalValueBlock();
}
转C++:
struct __VC__globalValueBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__globalValueBlock_block_desc_0* Desc;
__VC__globalValueBlock_block_impl_0(void *fp, struct __VC__globalValueBlock_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__globalValueBlock_block_func_0(struct __VC__globalValueBlock_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_4,globalV);
}
static struct __VC__globalValueBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __VC__globalValueBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__globalValueBlock_block_impl_0)};
static void _I_VC_globalValueBlock(VC * self, SEL _cmd) {
void(*globalValueBlock) (void) = ((void (*)())&__VC__globalValueBlock_block_impl_0((void *)__VC__globalValueBlock_block_func_0, &__VC__globalValueBlock_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)globalValueBlock)->FuncPtr)((__block_impl *)globalValueBlock);
}
- 2.6全局静态变量globalStaticV:未添加变量,而是直接使用全局区globalV
int static globalStaticV = 100;
//全局变量global value
- (void)globalStaticValueBlock {
void(^globalStaticValueBlock) (void) = ^ {
NSLog(@"简单实数Block -- %d",globalStaticV);
};
globalStaticValueBlock();
}
转C++
int static globalStaticV = 100;
struct __VC__globalStaticValueBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__globalStaticValueBlock_block_desc_0* Desc;
__VC__globalStaticValueBlock_block_impl_0(void *fp, struct __VC__globalStaticValueBlock_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__globalStaticValueBlock_block_func_0(struct __VC__globalStaticValueBlock_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_5,globalStaticV);
}
static struct __VC__globalStaticValueBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __VC__globalStaticValueBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__globalStaticValueBlock_block_impl_0)};
static void _I_VC_globalStaticValueBlock(VC * self, SEL _cmd) {
void(*globalStaticValueBlock) (void) = ((void (*)())&__VC__globalStaticValueBlock_block_impl_0((void *)__VC__globalStaticValueBlock_block_func_0, &__VC__globalStaticValueBlock_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)globalStaticValueBlock)->FuncPtr)((__block_impl *)globalStaticValueBlock);
}
- 2.7局部static value:添加指针变量
- (void)tempStaticValueBlock {
int static tempStaticV = 100;
void(^tempStaticValueBlock) (void) = ^ {
NSLog(@"简单实数Block -- %d",tempStaticV);
};
tempStaticValueBlock();
}
转C++
struct __VC__tempStaticValueBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__tempStaticValueBlock_block_desc_0* Desc;
int *tempStaticV;
__VC__tempStaticValueBlock_block_impl_0(void *fp, struct __VC__tempStaticValueBlock_block_desc_0 *desc, int *_tempStaticV, int flags=0) : tempStaticV(_tempStaticV) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__tempStaticValueBlock_block_func_0(struct __VC__tempStaticValueBlock_block_impl_0 *__cself) {
int *tempStaticV = __cself->tempStaticV; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_4722ae_mi_6,(*tempStaticV));
}
static struct __VC__tempStaticValueBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __VC__tempStaticValueBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__tempStaticValueBlock_block_impl_0)};
static void _I_VC_tempStaticValueBlock(VC * self, SEL _cmd) {
int static tempStaticV = 100;
void(*tempStaticValueBlock) (void) = ((void (*)())&__VC__tempStaticValueBlock_block_impl_0((void *)__VC__tempStaticValueBlock_block_func_0, &__VC__tempStaticValueBlock_block_desc_0_DATA, &tempStaticV));
((void (*)(__block_impl *))((__block_impl *)tempStaticValueBlock)->FuncPtr)((__block_impl *)tempStaticValueBlock);
}
- 2.8局部__block 修饰的变量:新增一个变量对应的结构体,通过结构体的__forwarding->blockV 获取值;新增__VC__blockValueBlock_block_copy_0(_Block_object_assign)、__VC__blockValueBlock_block_dispose_0(_Block_object_dispose)三个函数
- (void)blockValueBlock {
__block int blockV = 100;
void(^blockValueBlock) (void) = ^ {
NSLog(@"简单实数Block -- %d",blockV);
};
blockValueBlock();
}
转C++
struct __Block_byref_blockV_0 {
void *__isa;
__Block_byref_blockV_0 *__forwarding;
int __flags;
int __size;
int blockV;
};
struct __VC__blockValueBlock_block_impl_0 {
struct __block_impl impl;
struct __VC__blockValueBlock_block_desc_0* Desc;
__Block_byref_blockV_0 *blockV; // by ref
__VC__blockValueBlock_block_impl_0(void *fp, struct __VC__blockValueBlock_block_desc_0 *desc, __Block_byref_blockV_0 *_blockV, int flags=0) : blockV(_blockV->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __VC__blockValueBlock_block_func_0(struct __VC__blockValueBlock_block_impl_0 *__cself) {
__Block_byref_blockV_0 *blockV = __cself->blockV; // bound by ref
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_VC_29ca65_mi_7,(blockV->__forwarding->blockV));
}
static void __VC__blockValueBlock_block_copy_0(struct __VC__blockValueBlock_block_impl_0*dst, struct __VC__blockValueBlock_block_impl_0*src) {_Block_object_assign((void*)&dst->blockV, (void*)src->blockV, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __VC__blockValueBlock_block_dispose_0(struct __VC__blockValueBlock_block_impl_0*src) {_Block_object_dispose((void*)src->blockV, 8/*BLOCK_FIELD_IS_BYREF*/);}
static struct __VC__blockValueBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __VC__blockValueBlock_block_impl_0*, struct __VC__blockValueBlock_block_impl_0*);
void (*dispose)(struct __VC__blockValueBlock_block_impl_0*);
} __VC__blockValueBlock_block_desc_0_DATA = { 0, sizeof(struct __VC__blockValueBlock_block_impl_0), __VC__blockValueBlock_block_copy_0, __VC__blockValueBlock_block_dispose_0};
static void _I_VC_blockValueBlock(VC * self, SEL _cmd) {
__attribute__((__blocks__(byref))) __Block_byref_blockV_0 blockV = {(void*)0,(__Block_byref_blockV_0 *)&blockV, 0, sizeof(__Block_byref_blockV_0), 100};
void(*blockValueBlock) (void) = ((void (*)())&__VC__blockValueBlock_block_impl_0((void *)__VC__blockValueBlock_block_func_0, &__VC__blockValueBlock_block_desc_0_DATA, (__Block_byref_blockV_0 *)&blockV, 570425344));
((void (*)(__block_impl *))((__block_impl *)blockValueBlock)->FuncPtr)((__block_impl *)blockValueBlock);
}
- 2.9VC对block强引用(block是VC的属性时)其结构没有什么变化
三、Block源码浅析
(源码的浅析)
block源码地址
https://opensource.apple.com/source/libclosure/libclosure-79/
因此可以按照这个格式转换即可
https://opensource.apple.com/tarballs/libclosure/libclosure-79.tar.gz
- 首先来看
__block int a = 0;
void (^block) (void) = ^ {
NSLog(@"%d",a);
};
NSLog(@"%@",block);
这个block在是堆区还是在栈区?
在ARC下 NSMallocBlock
在MRC下 NSStackBlock
MRC下 那么栈区的block是怎么变成的堆区的block的呢?
实际上是执行_Block_copy 后栈区的block就变成堆区的block
_Block_copy源码
void *_Block_copy(const void *arg) {
struct Block_layout *aBlock; //申明一个block
if (!arg) return NULL; //如果源block(arg)为null直接返回
// The following would be better done as a switch statement
aBlock = (struct Block_layout *)arg;
if (aBlock->flags & BLOCK_NEEDS_FREE) {//需要释放,在堆区
// latches on high
latching_incr_int(&aBlock->flags);//堆区的block 执行copy操作,引用计数加1
return aBlock;
}
else if (aBlock->flags & BLOCK_IS_GLOBAL) {//在全局区
return aBlock; //全局区,保证全局唯一直接返回
}
else { //在栈局区
// Its a stack block. Make a copy.
size_t size = Block_size(aBlock); //获取结构体大小
struct Block_layout *result = (struct Block_layout *)malloc(size); //在堆区开辟对应的空间大小
if (!result) return NULL;
//复制 aBlock 所指的内存内容前 size 个字节到 result 所指的地址上
memmove(result, aBlock, size); // bitcopy first
#if __has_feature(ptrauth_calls)
// Resign the invoke pointer as it uses address authentication.
result->invoke = aBlock->invoke;
backtrace_symbols_fd(&result->invoke,1,1); //打印函数指针的对应的函数名称
#if __has_feature(ptrauth_signed_block_descriptors)
if (aBlock->flags & BLOCK_SMALL_DESCRIPTOR) {
uintptr_t oldDesc = ptrauth_blend_discriminator(
&aBlock->descriptor,
_Block_descriptor_ptrauth_discriminator);
uintptr_t newDesc = ptrauth_blend_discriminator(
&result->descriptor,
_Block_descriptor_ptrauth_discriminator);
result->descriptor =
ptrauth_auth_and_resign(aBlock->descriptor,
ptrauth_key_asda, oldDesc,
ptrauth_key_asda, newDesc);
}
#endif
#endif
//更新标志位。第一行确保引用计数为0。注释表明这行其实不需要——大概这个时候引用计数已经是0了。我猜保留这行是因为以前有个bug导致这里的引用计数不是0(所以说runtime的代码也会偷懒)。下一行设置了BLOCK_NEEDS_FREE标志位,表明这是一个堆block,一旦引用计数减为0,它所占用的内存将被释放。|1操作设置block的引用计数为1。
// reset refcount 重新设置引用计数
result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING); // XXX not needed
result->flags |= BLOCK_NEEDS_FREE | 2; // logical refcount 1
//这个是把剩下的需要复制到堆区的复制过来,例如__block 修饰的变量或block内使用的外部对象
_Block_call_copy_helper(result, aBlock);
// Set isa last so memory analysis tools see a fully-initialized object.
//block的isa指针被设置为_NSConcreteMallocBlock,说明这是个堆block。
result->isa = _NSConcreteMallocBlock;
return result;
}
}
从源码中可以看到if和else if的条件判断分别是引用计数(需要释放)和全局block的判断,如果是都直接返回block出去。else的条件判断就是栈block做copy操作。通过aBlock开启一个新的result空间,并且将aBlock的内容等平移到result中去。这时候就实现了由栈变成堆。
- 一个完整的执行流程
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block int a = 0;
void (^block) (void) = ^ {
NSLog(@"%d",a);
};
NSLog(@"%@",block);
block();
}
return 0;
}
通过clang -rewrite-objc main.m
会生成一个mian.cpp
的文件
__block int a = 0; 变量a对应的结构体
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
void (^block) (void) 对应的Block结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
NSLog(@"%d",a); 这句打印代码对应的函数,通过传入的__main_block_impl_0的实例__cself,__cself->a获取到a的值并打印
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a; // bound by ref
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pr_3v7lmlh17sd92x_qktr9b2w00000gn_T_main_6fbe70_mi_0,(a->__forwarding->a));
}
__main_block_copy_0函数是src的block结构体或者是src的block结构体持有的变量__Block_byref_a_0 复制到堆区
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
Block执行完后释放
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
Block结构体的附加描述信息
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
}
Block结构体的附加描述信息实例化
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
//__Block_byref_a_0 对应的变量a初始化:__block int a = 100;
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 100};
//block初始化
void(*voidBlock) (void) =((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
//block执行
((void (*)(__block_impl *))((__block_impl *)voidBlock)->FuncPtr)((__block_impl *)voidBlock);
}
return 0;
}
从C++的代码开__block int a = 0; 会生成__Block_byref_a_0这个结构体类型。
在.cpp 文件中有两个函数
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
其中__main_block_copy_0还调用了_Block_object_assign函数。通过源码可以找到这个函数的调用
void _Block_object_assign(void *destArg, const void *object, const int flags) {
const void **dest = (const void **)destArg;
switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
case BLOCK_FIELD_IS_OBJECT:
/*******
id object = ...;
[^{ object; } copy];
********/
_Block_retain_object(object);
*dest = object;
break;
case BLOCK_FIELD_IS_BLOCK:
/*******
void (^object)(void) = ...;
[^{ object; } copy];
********/
*dest = _Block_copy(object);
break;
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK: // __block | __weak 修饰的变量
case BLOCK_FIELD_IS_BYREF: //__block修饰的变量
/*******
// copy the onstack __block container to the heap
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__block ... x;
__weak __block ... x;
[^{ x; } copy];
********/
*dest = _Block_byref_copy(object);
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
/*******
// copy the actual field held in the __block container
// Note this is MRC unretained __block only.
// ARC retained __block is handled by the copy helper directly.
__block id object;
__block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
/*******
// copy the actual field held in the __block container
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__weak __block id object;
__weak __block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
default:
break;
}
}
这个段代码的就是当block或者Block_byrefs持有对象,就会通过这段代码来进行分配复制,从上面的代码可以知道在执行copy函数调用_Block_object_assign会将a的对象传进来。并且switch里面的枚举如下
// Runtime support functions used by compiler when generating copy/dispose helpers
// Values for _Block_object_assign() and _Block_object_dispose() parameters
enum {
// see function implementation for a more complete description of these fields and combinations
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...对象
BLOCK_FIELD_IS_BLOCK = 7, // a block variable 变量
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable __block修饰的变量
BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers __weak修饰的变量
BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines.
};
因为当前是__block修饰的就会执行到_Block_byref_copy函数里面去,传进去的是一个结构体.
static struct Block_byref *_Block_byref_copy(const void *arg) {
struct Block_byref *src = (struct Block_byref *)arg;
if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
// src points to stack
struct Block_byref *copy = (struct Block_byref *)malloc(src->size);
copy->isa = NULL;
// byref value 4 is logical refcount of 2: one for caller, one for stack
copy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;
copy->forwarding = copy; // patch heap copy to point to itself
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
// Trust copy helper to copy everything of interest
// If more than one field shows up in a byref block this is wrong XXX
struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1);
struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy+1);
copy2->byref_keep = src2->byref_keep;
copy2->byref_destroy = src2->byref_destroy;
if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) {
struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2+1);
struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2+1);
copy3->layout = src3->layout;
}
(*src2->byref_keep)(copy, src);
}
else {
// Bitwise copy.
// This copy includes Block_byref_3, if any.
memmove(copy+1, src+1, src->size - sizeof(*src));
}
}
// already copied to heap
else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
return src->forwarding;
}
这段代码大概的意思是将传进去的结构体重新创建一个,并且赋值相同的内存大小通过
copy->forwarding = copy; // patch heap copy to point to itself
src->forwarding = copy; // patch stack to point to heap copy
WeChat1186a2e029717109b1927b4859a73702.png
_Block_object_dispose函数调用时机及作用
当block从堆中移除时就会自动调用__main_block_desc_0中的__main_block_dispose_0函数,__main_block_dispose_0函数内部会调用_Block_object_dispose函数。
// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
// to help dispose of the contents
// 当 Blocks 或 Block_byrefs 持有对象时,它们的销毁助手例程调用此入口点
// 帮助处理内容
void _Block_object_dispose(const void *object, const int flags) {
switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
case BLOCK_FIELD_IS_BYREF:
// get rid of the __block data structure held in a Block
_Block_byref_release(object);
break;
case BLOCK_FIELD_IS_BLOCK:
_Block_release(object);
break;
case BLOCK_FIELD_IS_OBJECT:
_Block_release_object(object);
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
break;
default:
break;
}
}
四、Blokc性能分析
(Block用起来怎样呢?)
- block、delegate作用:
-
1.1能回调传值
-
1.2使对象与对象之间能通信交互
-
1.3改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度
- block优缺点
-
2.1 block优点:
省去了写代理的很多代码
block 更轻型,使用更简单,能够直接访问上下文,这样类中不需要存储临时数据,使用 block 的代码通常会在同一个地方,这样能连贯读代码
-
2.2 block缺点:
① block不够安全,使用 block 时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。
② block效率低,block出栈需要将使用的数据从栈内存拷贝到堆内存
③ 在多个通信事件的时候,block显得不够直观也不易维护。
-
block使用场景:
在1-2个通信事件的时候用block
-
delegate优缺点:
-
4.1 delegate优点:
① delegate更安全, delegate 的方法是分离开的,不会引用上下文,不容易循环引用
② delegate效率高,delegate只是保存了一个对象指针
③ 在多个通信事件的时候,delegate显得直观也易维护。
-
4.2 delegate缺点:
① 因方法的声明和实现分离开来,代码的连贯性不是很好,没有 block 好读
② 很多时候需要存储一些临时数据
-
4.3 delegate使用场景:
3个以上通信事件用delegate