block对变量捕获的方式

之前见很多文章对block捕获变量的方法,会进行诸如此类的描述:“block会捕获被引用的变量, 并对其进行copy操作, 因此, 可能会导致其引用计数加1,如果处理不好, 可能因循环引用导致内存泄漏。”

实际上, 这种说法并不严谨。block对变量的捕获, 根据变量类型的不同,会采用不同的捕获方式。

(1)静态或者全局变量, 在block中直接是指针传递的方式传入block中,对其进行的操作,在block内外是同步的。

(2)用__block修饰的变量,在传入block内部时, 会被包装成一个如下的结构体,其中的__forwarding就是变量的指针,在block中对变量的操作, 就是通过该字段来实现,因此block可以捕获外部对该变量的修改,block内部对变量的修改也会对外部生效

struct __Block_byref_a_0 {
 void *__isa;
__Block_byref_a_0 *__forwarding;
 int __flags;
 int __size;
 int a;
};

(3)更常见的OC对象或基本数据类型, block的捕获方式其实并不是对对象调用copy方法,而是进行值copy

举例1:

NSInteger num = 3;
NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){
    return n*num;
};
num = 1;
NSLog(@"%zd",block(2));

 输出为6,原因是block捕获num后创建了一个新的num对象, 其值为3, 后续在外部将num改为1无法被block捕获。即block内外&num的值, 我们可以发现是并不相同的。

举例2:

NSMutableArray * arr = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
void(^block)(void) = ^{
    NSLog(@"%@",arr);//局部变量
    [arr addObject:@"4"];
};
[arr addObject:@"3"];
arr = nil;
block();

输出1,2,3 。 这里虽然也是同样没有对NSMutableArray用__block修饰,但block里外arr对象是相同的,因此,block外部对arr的操作可以被block捕获。 但如果我们打印&arr, 就会发现block里外两个不同内存地址,但指向同一个NSMutableArray对象。

结论:对于基础类型和对象类型, 在block中进行赋值操作, 需要添加__block关键字,对于静态局部变量和全局变量, 就无需添加__block关键字。 对于非赋值操作,也无需添加__block关键字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值