本文主要是介绍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关键字。
这篇关于block对变量捕获的方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!