设为首页 加入收藏

TOP

block本质探寻一之内存结构(一)
2019-08-26 07:07:19 】 浏览:52
Tags:block 本质 探寻 内存 结构

一、代码——命令行模式

//main.m

#import <Foundation/Foundation.h>

struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};

struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    int age;
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
//        ^{
//            NSLog(@"This is a block");
//        }();
        
        int age = 10;
        void (^block)(int, int) = ^(int a, int b){
            NSLog(@"This is a block:%d", age);
            NSLog(@"a:%d b:%d", a, b);
        };
        
        struct __main_block_impl_0 *blockStruct = (__bridge struct __main_block_impl_0 *)block;
        

         block(20, 30);

    }
    return 0;
}

分析:以下代码的前提,因为我们知道block底层的构造就是上述结构体的构造,桥接的目的就是展示这样的结构体内部是怎样的;

struct __main_block_impl_0 *blockStruct = (__bridge struct __main_block_impl_0 *)block;

二、调试

//lldb模式

1)第一个断点

 

 2)第二个断点

 

3)转入汇编

 

 

4)汇编界面

 

 

分析:

1)我们发现内部变量的层次感:

第一层:包含impl、Desc、age;

第二层:impl包含isa、Flags、Reserved、FuncPtr;

2)block大括号内部的代码的第一行的地址跟FuncPtr指针指向的地址是一样的,那么block大括号内的代码是如何存放的,跟FuncPtr指针有什么关系?往下看;

 

 三、将main.m文件转成底层实现代码(即C++代码)

1)命令行:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

 

说明:警告不用管; 

 

2)找到main.cpp文件

 

3)拖入文件并打开

说明:不对mian.cpp文件编译的目的是,自己可以任意对该文件的代码操作而不报错; 

 

  

 

 说明:

1)上面两张图中,1、2、3是一一对应关系(1:为block要引用的外部变量;2:定义的block;3:调用block);

2)在2处,本人把一些强制转换去除了(如:void (*)等),便于阅读;

四、底层代码分析

1)block结构体(对2的分析)

很明显,block是一个指针,指向__main_block_impl_0,那__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(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是个结构体,内部成员变量有__block_impl类型的结构体变量,__main_block_desc_0类型的结构体变量,外部应用变量,以及一个__main_block_impl_0方法(该方法名跟所在的结构体名称相同,为C++的一个构造方法,类似于init方法);

<1>__block_impl

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

该结构体有四个成员变量,这跟上述lldb模式下显示的成员变量相同,而第一个成员变量为isa指针,我们知道这是oc对象(实例、类、元类)的专属标志,很显然__main_block_impl_0是一个oc对象,而oc对象的本质就是在内存中为结构体,此处完全吻合;

<2>__main_block_desc_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)};

该结构体有两个成员变量,同时定义了一个结构体变量并对其赋值,reserved赋值为0,Block_size赋值为__main_block_impl_0即block的内存大小;

<3>__main_block_impl_0构造函数

__main_block_impl_0在main 函数中传了三个参数:

//__main_block_func_0参数

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_tb_zgsq5gq15rd3zvbdmw1c09y80000gn_T_main_51dde3_mi_0, age);
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_tb_zgsq5gq15rd3zvbdmw1c09y80000gn_T_main_51dde3_mi_1, a, b);
        }

很显然,__main_block_func_0函数存放的是block大括号里面的代码,而该函数是直接赋值给__main_block_impl_0构造函数的第一个参数fp指针,而fp

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇block本质探寻二之变量捕获 下一篇dispatch_sync和dispatch_async的..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目