Block

2021-09-15  本文已影响0人  _一叶孤帆

定义

void (^名称)(参数) = ^{
};

使用

名称();

参考示例

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        int num = 1;
        void (^block)(void) = ^{
            NSLog(@"打印了 num = %d",num);
            NSLog(@"这个是 block");
        };
        
        block();
        
    }
    return 0;
}

原理解析

首先我们将上面的代码生成 cpp 文件看一下上面的代码会将我们的内容编译成什么样子

编译命令:

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

最终生成内容如下

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_0);

        int num = 1;
        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

    }
    return 0;
}

关键结构体有下面内容

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int num;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _num, int flags=0) : num(_num) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
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)};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int num = __cself->num; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_1,num);
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_2);
        }

可以发现我们最后的 block 定义其实是生成了一个结构体,并通过结构体的构造函数传递了三个参数。

&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num)

参数一:__main_block_func_0 则是我们实际执行的代码
参数二: __main_block_desc_0_DATA 是 block 的信息记录,Block_size 记录了 block 的大小。
参数三:num 则是我们访问的外部变量,赋值给了 block 内的变量 num

而且通过观察 __main_block_impl_0,我们可以发现此处也是生成了 isa 指针的,所以我们可以确认我们的 block 是一个对象。并且在构造函数中将传入的代码执行地址传递给了 impl 的 funcPtr, 在下面我们调用 block() 的时候实际也就是调用的 (impl->funcPtr)(num)

上一篇 下一篇

猜你喜欢

热点阅读