OC目标 – Block-目标类型的auto变量
1. Block内部拜访了目标类型的auto变量
当block内部拜访了目标类型的auto变量时,此刻block或许在栈上,也或许在堆上,不同类型的block所表现的动作是不一样的
1.1 根底代码
创立一个ZSXPerson类,在- (void)dealloc打印一下,这样咱们能够清楚看到ZSXPerson目标什么时候毁掉
@interface ZSXPerson : NSObject
@end
@implementation ZSXPerson
- (void)dealloc {
[super dealloc];
NSLog(@"ZSXPerson --- %s", __func__);
}
@end
main.m
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目标
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结构体中持有
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类型的
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


