文章目录
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