Block

作者: _一叶孤帆 | 来源:发表于2021-09-15 18:33 被阅读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)

相关文章

  • iOS开发之Block原理探究

    Block概述 Block本质 Block调用 Block分类 Block循环引用 Block原理探究 Block...

  • block的使用

    定义block 返回类型 (^block名称)(参数) = ^(){block内容}; 调用block block...

  • Block 02 - __block

    Block 02 - __block __block 的作用 __block 可以解决 Block 内部无法修改 ...

  • iOS面试之Block大全

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • iOS面试之Block模块

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • iOS Block

    Block的分类 Block有三种类型:全局Block,堆区Block,栈区Block 全局Block 当Bloc...

  • iOS block 为什么官方文档建议用 copy 修饰

    一、block 的三种类型block 三种类型:全局 block,堆 block、栈 block。全局 block...

  • iOS开发block是用copy修饰还是strong

    Block分为全局Block、堆Block和栈Block1、在定义block没有引用外部变量的时候,block为全...

  • block 初探

    全局block, 栈block, 堆block

  • Block

    一、Block本质 二、 BlocK截获变量 三、__block 修饰变量 四、Block内存管理 五、Block...

网友评论

      本文标题:Block

      本文链接:https://www.haomeiwen.com/subject/wmrkgltx.html