OC对象 - Block-对象类型的auto变量
1. Block内部访问了对象类型的auto变量
当block内部访问了对象类型的auto变量时,此时block可能在栈上,也可能在堆上,不同类型的block所表现的动作是不一样的
1.1 基础代码
创建一个ZSXPerson类,在- (void)dealloc打印一下,这样我们可以清楚看到ZSXPerson对象什么时候销毁
less
@interface ZSXPerson : NSObject
@end
@implementation ZSXPerson
- (void)dealloc {
[super dealloc];
NSLog(@"ZSXPerson --- %s", __func__);
}
@end
main.m
csharp
int main(int argc, const char * argv[]) {
@autoreleasepool {
{
ZSXPerson *person = [[ZSXPerson alloc] init];
}
NSLog(@"-----");
}
return 0;
}
在{}内,初始化一个ZSXPerson对象,然后在在{}外打了断点 
可以看到person对象出了{}会马上销毁
接下来我们在此基础上,尝试不同 block 对person对象销毁时机的影响
1.2 Block访问person对象
增加一个block,内部访问person对象
ini
ZSXBlock block;
{
ZSXPerson *person = [[ZSXPerson alloc] init];
person.age = 10;
block = ^ {
NSLog(@"%d", person.age);
};
}
NSLog(@"block - %@", [block class]);
NSLog(@"-----");
此时断点停留在{}之后,按理说 person 已经出了作用域了,但实际却没有销毁
我们断点继续往下走
出了@autoreleasepool之后,person才销毁。这时候刚好 block 也已经出了作用域,block是会销毁的。因此,block里面对person有强引用,所以出了第一个{}的时候,虽然person已经走出作用域,但是此时block还在作用域内,它还持有person,所以person并不会释放
1.2.1 查看底层实现
block访问对象类型的auto变量后
- block结构体中持有
person成员的指针 __main_block_desc_0结构体中多了copy和dispose两个函数。这两个函数是用来管理block所持有变量的持有关系的
因为block里面持有了对象,对象本身在内存中是通过引用计数来管理内存的,因此block也需要对其负责内存管理
1.3 NSStackBlock类型block访问对象类型
NSStackBlock类型block本身就是随时可能释放的,所以NSStackBlock类型的block没有必要强持有访问对象
1.3.1 修改代码
代码中我们不使用strong变量接收block,这时候的block就是NSStackBlock类型的
ini
ZSXBlock block;
{
ZSXPerson *person = [[ZSXPerson alloc] init];
person.age = 10;
^ {
NSLog(@"%d", person.age);
};
}
NSLog(@"block - %@", [block class]);
NSLog(@"-----");
打印结果:
person出了作用域马上就释放了,因此可以说明这时候的block并没有持有person。
2. 总结
当block内部访问了对象类型的auto变量时
-
如果block是在
栈上,将不会对auto变量产生强引用 -
如果block被
拷贝到堆上- 会调用block内部的
copy函数 - copy函数内部会调用
_Block_object_assign函数 - _Block_object_assign函数会根据auto变量的
修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
- 会调用block内部的
-
如果block从堆上
移除- 会调用block内部的
dispose函数 - dispose函数内部会调用
_Block_object_dispose函数 - _Block_object_dispose函数会
自动释放引用的auto变量(release)
- 会调用block内部的

@oubijiexi