iOS Block

  • Post category:Objective-C

Block 是什么?它内部的数据结构是什么样的?

我这边写了一个 BlockTestClass 类里面的代码如下:

#import "BlockTestClass.h"

@implementation BlockTestClass

- (void)testMethods{

    void (^BlockMethod)(int input) = ^(int input){
        NSLog(@"%d",input);
    };
    if (BlockMethod) {
        BlockMethod(2026);
    }
}
@end

打开终端 cd 到 BlockTestClass.m 所在文件夹执行下面的代码将 OC 转换成 C++ 执行完之后会在当前文件夹新增一个 BlockTestClass.cpp 文件

clang -rewrite-objc BlockTestClass.m 

得到 c++代码


// - (void)testMethods;
/* @end */

#pragma clang assume_nonnull end

// @implementation BlockTestClass

struct __BlockTestClass__testMethods_block_impl_0 {
  struct __block_impl impl;
  struct __BlockTestClass__testMethods_block_desc_0* Desc;
  __BlockTestClass__testMethods_block_impl_0(void *fp, struct __BlockTestClass__testMethods_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __BlockTestClass__testMethods_block_func_0(struct __BlockTestClass__testMethods_block_impl_0 *__cself, int input) {

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_mf_mbzvp10j21vggsw04my_j31m0000gn_T_BlockTestClass_9d202b_mi_0,input);
    }

static struct __BlockTestClass__testMethods_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __BlockTestClass__testMethods_block_desc_0_DATA = { 0, sizeof(struct __BlockTestClass__testMethods_block_impl_0)};

static void _I_BlockTestClass_testMethods(BlockTestClass * self, SEL _cmd) {
    void (*BlockMethod)(int input) = ((void (*)(int))&__BlockTestClass__testMethods_block_impl_0((void *)__BlockTestClass__testMethods_block_func_0, &__BlockTestClass__testMethods_block_desc_0_DATA));
    if (BlockMethod) {
        ((void (*)(__block_impl *, int))((__block_impl *)BlockMethod)->FuncPtr)((__block_impl *)BlockMethod, 2026);
    }
}

// @end

通过上面的代码 Block 是封装了函数和上下文的结构体对象

它会根据 类名方法名_block_impl_下标 (0代表这个方法或者这个类中第0个block 下面如果还有将会 第1个block 第2个…)

一个变量被 __block 修饰的区别?


 @implementation BlockTestClass

- (void)testMethodsTwo {
    __block int a = 10;
    void (^BlockMethodTwo)(void) = ^{
        a += 1;
        NSLog(@"a=%d",a);
    };
    if (BlockMethodTwo) {
        BlockMethodTwo();
    }
}

输出结果 a=11

继续生成对应的 c++文件

// __block 变量的底层结构
// @implementation BlockTestClass

struct __Block_byref_a_0 {
  void *__isa;
__Block_byref_a_0 *__forwarding;// 关键!指向自身的指针
 int __flags;
 int __size;
 int a;
};

多了一个 __Block_byref_a_0

block 将变量包装成结构体,通过 forwarding 指针实现在堆栈间正确访问

理解这些底层机制有助于编写正确、高效的 Block 代码