OC对象 - Block内存管理
1. block从栈拷贝到堆
- 当block在栈上时,并不会对__block变量产生强引用
- 当block被copy到堆时
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会对__block变量形成强引用(retain)
1.1 分析
- 假设有
__block变量,Block0、Block1都使用__block变量 - 此时
__block变量,Block0、Block1都是在栈上,Block0、Block1并没有对__block变量产生强引用 - 当
Block0复制到堆上时,同时会把__block变量复制到堆上,并且强引用__block变量

- 接着
Block1也复制到堆上时,在此之前__block变量已经复制到堆上了,Block1此时也会强引用__block变量

2 block从堆中移除
- 当block从堆中移除时
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的__block变量(release)
2.1 分析
2.1.1 单个block持有
Block从堆中移除时,会释放引用的__block变量- 此时
__block变量没有其他持有者了,因此也销毁了

2.1.2 多个block持有
Block0、Block1都持有__block变量Block0从堆中移除时,会释放对__block变量的引用- 此时
__block变量还被Block1引用着 Block1也从堆中移除,也释放对__block变量的引用- 此时
__block变量没有其他持有者了,因此也销毁了

3. block的__forwarding指针
使用__block修饰的变量,编译器会将__block变量包装成一个对象,对象对应的结构体如下
注意到里面的__forwarding,并且在修改值的时候,它也是通过访问包装对象的__forwarding,再访问将要操作的变量

3.1 原因
block使用过程中,是可能从栈上拷贝到堆上的,__forwarding是指向自己的指针,当block在栈上时,他指向的是栈上的自己
当block拷贝到堆上后,栈上的block的__forwarding指向复制到堆上的__block变量用结构体的指针,堆上的block的__forwarding指向的还是自己本身的指针
这就可以保证,block复制到堆上后,不管使用栈上的block,还是堆上的block,都能通过__forwarding访问堆上的block
4. 对象类型的auto变量 VS 添加__block修饰符的变量
__block int age = 10;
ZSXPerson *person = [[ZSXPerson alloc] init];
ZSXBlock block = ^ {
age = 20;
NSLog(@"age is %d", age);
NSLog(@"person is %d", person);
};

4.1 当block在栈上时,对它们都不会产生强引用
4.2 当block拷贝到堆上时,都会通过copy函数来处理它们
- __block变量(假设变量名叫做a)
- _Block_object_assign((void*)&dst->a, (void*)src->a, 8/BLOCK_FIELD_IS_BYREF/);
- 对象类型的auto变量(假设变量名叫做p)
- _Block_object_assign((void*)&dst->p, (void*)src->p, 3/BLOCK_FIELD_IS_OBJECT/);
4.3 当block从堆上移除时,都会通过dispose函数来释放它们
- __block变量(假设变量名叫做a)
- _Block_object_dispose((void*)src->a, 8/BLOCK_FIELD_IS_BYREF/);
- 对象类型的auto变量(假设变量名叫做p)
- _Block_object_dispose((void*)src->p, 3/BLOCK_FIELD_IS_OBJECT/);

@oubijiexi