【iOS面试粮食】Block

本文章将记录Objective-C中Block的相关资料,如有错误欢迎指出~

Block的本质

Block本质.png

Block 实际上就是一个OC对象(结构体中有 isa 指针),这个对象封装了函数,以及函数执行的上下文

Block的变量捕获

为了保证block内部能够正常访问外部的变量,block有一个变量捕获机制。block捕获外部变仅仅只捕获Block闭包里面会用到的值,其他用不到的值,它并不会去捕获。

局部变量

看下简单的代码输出

auto int age = 10;
static int num = 25;
void (^Block)(void) = ^{
    NSLog(@"age:%d,num:%d",age,num);
};
age = 20;
num = 11;
Block();

// log   age = 10
                 age = 11
  • auto变量
    • auto自动变量,离开作用域就销毁,通常局部变量前面自动添加auto关键字。自动变量会捕获到block内部,也就是说block内部会专门新增加一个参数来存储变量的值。 auto只存在于局部变量中,访问方式为值传递。
  • static变量
    • static 修饰的变量为指针传递,同样会被block捕获。

为什么两种变量会有这种差异呢?

因为自动变量可能会销毁,block在执行的时候有可能自动变量已经被销毁了,那么此时如果再去访问被销毁的地址肯定会发生坏内存访问,因此对于自动变量一定是值传递而不可能是指针传递了。

而静态变量不会被销毁,所以完全可以传递地址。而因为传递的是值得地址,所以在block调用之前修改地址中保存的值,block中的地址是不会变得。所以值会随之改变。

全局变量

因为全局变量无论在哪里都可以访问,所以block不需要捕获全局变量

变量类型

总结:

  • 局部变量都会被block捕获,自动变量是值捕获,静态变量为地址捕获

  • 全局变量则不会被block捕获

Block的类型

OC中,一般Block就分为以下3种类型

  • __NSGlobalBlock__( _NSConcreteGlobalBlock ),即没有用到外界变量或只用到全局变量、静态变量的block。生命周期从创建到应用程序结束,直到程序结束才会被回收,不过我们很少使用到__NSGlobalBlock__类型的block,因为这样使用block并没有什么意义。
  • __NSStackBlock__( _NSConcreteStackBlock ),即只用到外部局部变量、成员属性变量,且没有强指针引用的block。__NSStackBlock__类型的block存放在栈中,我们知道栈中的内存由系统自动分配和释放,作用域执行完毕之后就会被立即释放,而在相同的作用域中定义block并且调用block似乎也多此一举。
  • __NSMallocBlock__( _NSConcreteMallocBlock ),即有强指针引用或copy修饰的成员属性引用的block 。存放在堆中,没有强指针引用即销毁,需要我们自己进行内存管理。
Block的类型.png

Block的循环引用

这篇文章讲的挺不错的Block 与 self 的那点事(iOS)

面试题

面试题请参考 这篇文章 iOS-Block相关面试题

参考

iOS底层原理总结 - 探寻block的本质(一)

iOS block 捕获外部变量以及注意点

你可能感兴趣的:(【iOS面试粮食】Block)