iOS 底层 被__block修饰的对象类型 - AlvinSunny/OC-TheUnderlying GitHub Wiki
被__block修饰的对象会发生什么 ?
-
当__block变量在栈上时,不会对指向的对象产生强引用
-
当__block变量被copy到堆上时
- 会调用__block变量内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_umrefained)做出相应操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC环境会retain, MRC是不会retain,就是说一直都是弱引用)
- 如果__block变量从堆上移除
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放(对 __block 修饰的变量进行一次release操作,引用计数器减一;注意只是引用计数器减一不一定达到释放条件)引用的 __block 变量
##代码演示
源代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block XYHPerson *person = [[XYHPerson alloc] init];
XYHBlock block = [^{
NSLog(@"%p", person);
} copy];
block();
}
return 0;
}
转c++后的核心代码
struct __Block_byref_person_0 {
void *__isa; // 8
__Block_byref_person_0 *__forwarding; // 8
int __flags; // 4
int __size; // 4
void (*__Block_byref_id_object_copy)(void*, void*); // 8
void (*__Block_byref_id_object_dispose)(void*); // 8
XYHPerson *__strong person; -- > block内部对person对象是请引用
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_person_0 *person; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_person_0 *_person, int flags=0) : person(person->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
图解

如果在使用__block时用 __weak 修饰 person 对象 , __Block_byref_person_0 内部对其是强引用吗 ?
答:不是,是弱引用;

MRC是不会retain,就是说一直都是弱引用说明(默认block内部访问的对象是经过__block修饰的)

疑问:ARC 环境 如果去掉__block修饰person还会提前释放吗 ?为什么 ?有什么风险吗 ?
答: 不会提前释放; 因为不使用__block修饰时,block内部就是直接访问person对象,person会在main函数执行完释放; 在这段简单的代码中是没有风险的,但是在日常开发中若person是当前类的属性时,直接使用可能会造成循环引用。