iOS底层 -- Blcok本质之__Block修饰符
2020-09-10 本文已影响0人
happy神悦
一、__Block修饰auto变量
- __block可以用于解决block内部无法修改auto变量值的问题
- __block不能修饰全局变量、静态变量(static)
定义一个__block修饰的auto变量
Block block;
__block int age = 10;
block = ^{
age = 20;
NSLog(@"%d", age);
};
block();
编译器会将__block变量包装成一个对象(结构体)
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_age_0 *age; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_age_0 {
void *__isa; // isa指针
__Block_byref_age_0 *__forwarding; // 指向自身的指针
int __flags;
int __size; // 结构体的大小
int age; // auto变量的值
};
二、__block内存管理
1.当block在栈上时,并不会对__block变量产生强引用
2.当block被拷贝到堆上
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会对__block变量形成强引用(retain)
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst->objc, (void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
3.当block从堆中移除时
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放指向的对象(release)
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
三、_forwarding指针的作用
复制之前:
age(栈区age结构体)->_forwarding(指向自己的指针)->age(age成员变量值)
复制之后:
age(栈区age结构体)->_forwarding(指向堆区age结构体)->age(age成员变量值)
四、__block修饰对象类型
1.当__block变量在栈上时,不会对指向的对象产生强引用
2.当__block变量被copy到堆时
- 会调用__block变量内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)
强引用:
Block block;
__block Person *person = [[Person alloc] init];
block = ^{
NSLog(@"%@", person);
};
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
nt __size;
void (*__Block_byref_id_object_copy)(void*, void*);//从栈上复制到堆上要进行的操作
void (*__Block_byref_id_object_dispose)(void*);//从堆上移除要进行的操作
Person *person;//强引用
};
弱引用:
Block block;
Person *person0 = [[Person alloc] init];
__block __weak Person *person = person0;
block = ^{
NSLog(@"%@", person);
};
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);//从栈上复制到堆上要进行的操作
void (*__Block_byref_id_object_dispose)(void*);//从堆上移除要进行的操作
Person *__weak person;//弱引用
};
3.当__block变量从堆上移除
- 会调用__block变量内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放指向的对象(release)