Block底层原理(一)

本文详细解析了Block的本质,包括其在不同场景下的实现机制,如无参数、有参数及捕获局部变量的情况,并探讨了Block在C++中的底层表示,以及在Objective-C中不同类型的Block(如NSGlobalBlock、NSMallocBlock和NSStackBlock)的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)block的本质,是一个结构体
__main_block_impl_0是结构体类型,__block_impl储存着block的基本信息,比如isa指针和funcPtr-block块代码实现,__main_block_desc_0储存着block的大小等

(二)捕获变量
第一种:没有参数,在block中打印,无需捕获

        void (^block)(void) = ^{
            NSLog(@"Hello, World!");
        };

编译成c++代码后(xcrun -sdk phones clang -arch arm64 -rewrite-objc 要编译的文件)如何获取c++文件

        // 定义block变量
        void (*block)(void) = &__main_block_impl_0(
                                                   __main_block_func_0,
                                                   &__main_block_desc_0_DATA
                                                   );

        // 执行block内部的代码
        block->FuncPtr(block);
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  // 构造函数(类似于OC的init方法),返回结构体对象
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
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_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_c60393_mi_0);
        }

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内有参数传入(无捕获)

        void (^block)(int, int) = ^(int a, int b){
            NSLog(@"Hello, World! - %d %d", a, b);
        };

        block(10, 20);

在c++中如何展示

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

        block->FuncPtr(block, 10, 20);

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    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 a, int b) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_87bc8b_mi_0, a, b);
        }

(三)block内部访问了局部变量
( int age = 10,被capture,值传递; static int height = 10;被capture,指针传递)

  void test()
{
    int age = 10;
    static int height = 10;
    
    block = ^{
        // age的值捕获进来(capture)
        NSLog(@"age is %d, height is %d", age, height);
    };
    
    age = 20;
    height = 20;
}

       test();
       block();
       

在c++内部如何显示

   test();
  ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
void test()
{
    int age = 10;
    static int height = 10;

    block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &height));

    age = 20;
    height = 20;
}
struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
  int age;
  int *height;
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
static struct __test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};

block的类型:NSGlobalBlock NSMallocBlock NSStackBlock
三种

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int a = 10;
        
        // 堆:动态分配内存,需要程序员申请申请,也需要程序员自己管理内存
        void (^block1)(void) = ^{
            NSLog(@"Hello");
        };
        
        int age = 10;
        void (^block2)(void) = ^{
            NSLog(@"Hello - %d", age);
        };
        
        NSLog(@"%@ %@ %@", [block1 class], [block2 class], [^{
            NSLog(@"%d", age);
        } class]);
    }
    return 0;
}
打印结果如图
![block1未访问任何变量,为__NSGlobalBlock__ ;block访问了局部变量,本为stack,但在ARC下,自动copy变为malloc
](https://img-blog.csdnimg.cn/20181215221333568.png)

以下为总结:
|访问了auto变量| stack |经过copy变成malloc
|没有访问auto变量|global|经过copy,无任何改变
| copy stack类型的block 后|变为malloc |再copy后,retaincount+1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值