OC底层-Block本质(四、copy和strong)

275 阅读2分钟

在ARC环境下,编译器会根据情况自动将栈上的block进行一次copy操作,将block复制到堆上。

什么情况下ARC会自动将block进行一次copy操作?以下代码都在ARC环境下执行。

block作为函数返回值时

typedef void (^Block)(void);
Block myblock()
{
    int a = 10;
    Block block = ^{
        NSLog(@"---------%d", a);
    };
    return block;
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block = myblock();
        block();
       
        NSLog(@"%@",[block class]);
        // 打印block类型为 __NSMallocBlock__
    }
    return 0;
}

如果在block中访问了auto变量时,block的类型为__NSStackBlock__,上面打印内容发现blcok为__NSMallocBlock__类型的,并且可以正常打印出a的值,说明block内存并没有被销毁。 block进行copy操作会转化为__NSMallocBlock__类型,说明block是复制到堆上了,那么说明在ARC环境下, block作为函数返回值时编译器会自动帮助我们对block进行copy操作,以保存block,并在适当的地方进行release操作。

将block赋值给__strong指针时

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // block内没有访问auto变量   __NSGlobalBlock__ 类型
        Block block1 = ^{
            NSLog(@"block---------");
        };
        NSLog(@"1. %@",[block1 class]);
        int a = 10;
        // block内访问了auto变量,但没有赋值给__strong指针 __NSStackBlock__ 类型
        NSLog(@"2.%@",[^{
            NSLog(@"block2---------%d", a);
        } class]);
        // block赋值给__strong指针  __NSMallocBlock__ 类型
        Block block3 = ^{
          NSLog(@"block2---------%d", a);
        };
        NSLog(@"3.%@",[block3 class]);
    }
    return 0;
}

查看打印内容可以看出,当block被赋值给__strong指针时,ARC会自动进行一次copy操作。

block作为Cocoa API中方法名含有usingBlock的方法参数时

遍历数组的block方法,将block作为参数的时候

NSArray *array = @[@"1",@"2"];
  
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

}];

block作为GCD API的方法参数时

GCD的一次性函数或延迟执行的函数,执行完block操作之后系统才会对block进行release操作。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
            
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
});

通过上面对MRC及ARC环境下block的不同类型的分析,总结出不同环境下block属性建议写法。

MRC下block属性的建议写法

@property (copy, nonatomic) void (^block)(void);

ARC下block属性的建议写法

@property (strong, nonatomic) void (^block)(void);

@property (copy, nonatomic) void (^block)(void);

何时使用copy和strong

这个是基础,如果不清楚,可以自己去验证