0%

Objective-C:Block

变量捕获机制

  • 全局变量:不会捕获到block内部,直接访问。
  • auto基本类型的局部变量,捕获到block内部,生成成员变量来存储,以值传递的方式访问。
  • static类型的局部变量:捕获到block内部,生成成员变量来存储,以指针方式访问。
  • 对象类型的局部变量:连同它的所有权修饰符一起捕获。

变量捕获修饰符

  • __weak是为了防止循环引用。在block中访问weak指针,当对象被释放时,指针置空,变成nil调用相关方法。
  • __strong是为了延长生命周期。这里用在block和目标对象存在相互引用的关系才有效,且赋值的是weak指针,作用是使其引用计数+1。相当于声明了个局部变量。
  • __block是为了在block内部可以修改外部的变量。
    • 如果想用__block解决循环引用,必须要在block中将其修饰的变量置空。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self dismissViewControllerAnimated:true completion:nil];

__weak typeof(self) _self = self;
TestViewController *tmp = self;
self.block = ^{
// 1⃣️
// 注意声明是发生在这里,即weak self指向的对象还没被销毁的时候
__strong typeof(_self) s_self = _self; // 同下
// TestViewController *s_self = _self;
// TestViewController *s_self = tmp; // 还是导致循环引用
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2⃣️
NSLog(@"block属性延时weak: %@, strong: %@", _self, s_self);
// weak == strong != nil
});
};
self.block();
}

注意,给__strong变量赋值的弱引用必须在弱引用指向的对象还没被销毁的时候完成赋值,否则拿到的弱引用是个nil。

另外,如果只是在1⃣️处定义并赋值了强引用对象,而在2⃣️处没有使用,则2⃣️处访问的弱引用也是空的。

底层数据结构

block本质也是一个OC对象,内部也有个isa指针。封装了函数调用以及调用环境。

参考

欢迎关注我的其它发布渠道