美文网首页iOS底层原理
小码哥底层原理笔记:Block的底层结构

小码哥底层原理笔记:Block的底层结构

作者: chilim | 来源:发表于2020-05-29 15:09 被阅读0次

我们准备一个简单的block代码:

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        
        int age = 10;
        void (^block)(int, int) = ^(int a, int b){
            NSLog(@"this is a block age:%d", age);
            NSLog(@"this is a block");
        };
        block(20,20);
}
}

将这段代码翻译成C++代码如下:

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

        appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));

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

        ((void (*)(__block_impl *, int, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 20, 20);
    }
    return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}

再将这段代码简化一下,把里面的强制类型转换可以去掉:

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

        appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));

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

        block->FuncPtr(block, 20, 20);
    }
    return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}

现在清晰明了,我们定义的一个block实质是一个__main_block_impl_0函数的指针,因为我们看到是直接取__main_block_impl_0函数的地址赋值给block的。
通过源码可以知道__main_block_impl_0的结构是这样的:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int age;//捕获的变量
//这是一个构造方法,实际上这个__main_block_impl_0就只有上面这三个参数
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

我们把上面这个构造方法去掉,实际上__main_block_impl_0就只有三个参数 struct __block_impl impl;、 struct __main_block_desc_0* Desc;和int age,age很好理解,就是block捕获的age变量。__block_impl的结构是这样:

struct __block_impl {
  void *isa;//isa指针
  int Flags;
  int Reserved;
  void *FuncPtr;//block封装的函数指针
};

__main_block_desc_0的结构是这样:

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;//保存block的大小
}

里面的结构都清楚了,我们再回头看下block的定义那段代码:

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

我们可以看到在定义block的时候__main_block_impl_0函数接收了三个参数,其中__main_block_func_0就是block里面执行的那段代码,这里是封装成了这样一个函数:

static void __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
  int age = __cself->age; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_y0_thwqbdb11zq5wklyb8jyy4km0000gn_T_main_76632f_mi_0, age);
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_y0_thwqbdb11zq5wklyb8jyy4km0000gn_T_main_76632f_mi_1);
        }

__main_block_desc_0_DATA这个函数是用来获取block占用内存大小的:

__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

当我们把这三个参数传进去之后会在__main_block_impl_0构造方法里面赋值保存起来:

 __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }

其中block里面封装的那段代码的函数地址会赋值给__block_implFuncPtr,block占用内存大小信息则赋值给__main_block_impl_0里面的Desc这里还给__block_impl的isa指针赋值了,__block_impl的flag默认是赋值了0。

简单说一个Block,它的底层结构就是这样:

struct __main_block_impl_0 {
  void *isa;//isa指针
  int Flags;
  int Reserved;
  void *FuncPtr;//block内部代码封装的函数指针
  struct __main_block_desc_0* Desc;//block大小等信息
  int age;//捕获的外部参数
};

我们直接把__block_impl结构体拿进来,把构造函数去掉之后就是这样一个结构体了。我们发现block的第一个属性就是isa指针,所以block实际上也是一个OC对象。

相关文章

网友评论

    本文标题:小码哥底层原理笔记:Block的底层结构

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