Block 原理以及面试题

713 阅读2分钟
1.Block的本事是什么?
2.Block变量捕获
3.Block内存管理
4.Block的修饰符 __block

问题1:Block的本质是封装了函数以及函数上下文的对象。

int main(int argc, const char * argv[]) {    @autoreleasepool {        void(^printBlock)(void) = ^() {
            NSLog(@"block print");
        };        printBlock();    }    return 0;}

通过clang命令转换成cpp文件查看编译器把Block解析成什么

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

//1.先看这里
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        void(*printBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
        ((void (*)(__block_impl *))((__block_impl *)printBlock)->FuncPtr)((__block_impl *)printBlock);
    }
    return 0;
}

//2.看这个函数
struct __main_block_impl_0 {
  struct __block_impl impl;//看下面__block_impl 实现里面有个isa
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;//这是Block内存stack一种
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//3isa可以说明block本质上是oc的对象
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

//block 函数体
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_73_gxjqw_b94kz_9bcxk58jxb240000gn_T_main_38ac7a_mi_0);
        }

//block 函数描述
static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

Block变量捕获

//转换前的代码
//全局变量int global_var = 11;//静态全局变量static int static_global_var = 10;int main(int argc, const char * argv[]) {    @autoreleasepool {        //局部变量
        int number = 10;      //对象

         __unsafe_unretained id obj = nil;        //静态局部变量      static int multiplier = 20;void(^printBlock)(void) = ^() {
NSLog(@"multiplier=%d",multiplier);
NSLog(@"obj=%@",obj);
NSLog(@"number=%d",number);
NSLog(@"global_var = %d",global_var);
 };
printBlock();
 }
return 0;}
//转换后的代码
int global_var = 11;

static int static_global_var = 10;


struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int *multiplier;
  id obj;
  int number;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_multiplier, id _obj, int _number, int flags=0) : multiplier(_multiplier), obj(_obj), number(_number) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

  • 局部变量:值捕获
  • 静态变量:指针捕获
  • 全局变量:不捕获
看考题?

@autoreleasepool {
        //局部变量
        int number = 10;
        //对象
        __unsafe_unretained id obj = nil;
        //静态局部变量
        static int multiplier = 20;
        void(^printBlock)(int a) = ^(int a) {
            NSLog(@"multiplier=%d",multiplier);
            NSLog(@"obj=%@",obj);
            NSLog(@"number=%d",number * a);
            NSLog(@"global_var = %d",global_var);
        };
        number = 9;
        printBlock(3);//number打印30 还是27            }

Block的修饰符

       NSMutableArray *array = [NSMutableArray arrayWithCapacity:5];
        void(^block)(void) = ^{
            [array addObject:@"3333"];
            NSLog(@"array:%@",array);
        };
        block();问打印什么会会不报异常呢?    }

  case2
        __block NSMutableArray *array = nil;
        void(^block)(void) = ^{
            array = [NSMutableArray array];
            [array addObject:@"333"];
            NSLog(@"array:%@",array);
        };
        block();//打印什么
    }

Block的内存分布
  1. 全局Block     GloabalBlock
  2. 栈上Block     StackBlock
  3. 堆上的Block  MallocBlock
__block修饰符

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_array_0 *array; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_array_0 *_array, int flags=0) : array(_array->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }