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目标,然后在在{}外打了断点

OC目标 - Block-目标类型的auto变量

能够看到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(@"-----");

OC目标 - Block-目标类型的auto变量
此刻断点停留在{}之后,按理说 person 现已出了效果域了,但实践却没有毁掉

咱们断点持续往下走

OC目标 - Block-目标类型的auto变量
出了@autoreleasepool之后,person才毁掉。这时候刚好 block 也现已出了效果域,block是会毁掉的。因而,block里面临person有强引证,所以出了第一个{}的时候,虽然person现已走出效果域,可是此刻block还在效果域内,它还持有person,所以person并不会开释

1.2.1 检查底层完成

OC目标 - Block-目标类型的auto变量
block拜访目标类型的auto变量后

  • block结构体中持有person成员的指针
  • __main_block_desc_0结构体中多了copydispose两个函数。这两个函数是用来办理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(@"-----");

打印成果:

OC目标 - Block-目标类型的auto变量
person出了效果域马上就开释了,因而能够说明这时候的block并没有持有person

2. 总结

block内部拜访了目标类型的auto变量时

  • 如果block是在栈上,将不会对auto变量产生强引证

  • 如果block被拷贝到堆上

    1. 会调用block内部的copy函数
    2. copy函数内部会调用_Block_object_assign函数
    3. _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引证(retain)或者弱引证
  • 如果block从堆上移除

    1. 会调用block内部的dispose函数
    2. dispose函数内部会调用_Block_object_dispose函数
    3. _Block_object_dispose函数会主动开释引证的auto变量(release)

OC目标 - Block-目标类型的auto变量

@oubijiexi