Substantial learning summary of Blocks

update record

time Revision
April 12, 2020 First draft

Foreword

  • At present, the Blocks blogs searched on the Internet are generally based on the classic book "Objective-C Advanced Programming iOS and OS X Multithreading and Memory Management".
  • This article is similar, and I will add my own summary and thinking as much as possible.

The essence of Blocks

Convert Objective-C code to C / C ++ code

  • clang -rewrite-objc source code file name

Simple block declaration

int main(int argc, const char * argv[]) {
    void (^blk)(void) = ^{
        printf("Block\n");
    };
    blk();
    return 0;
}

The converted C / C ++ code

//block的实现
struct __block_impl {
  //由于第一个成员变量是isa指针,其实是一个OC对象。本对象中记录了block函数对应的函数指针

  void *isa;        //block isa指针,指向类对象(stack、malloc、global三种类型之一)
  int Flags;        //某些标志,暂不深入研究
  int Reserved;     //保留区域,以后版本升级可能会用到
  void *FuncPtr;    //函数指针
};

//这就是block本身对应的结构
struct __main_block_impl_0 {
  //只有两个成员变量。其中impl是一个OC对象

  struct __block_impl impl;
  struct __main_block_desc_0* Desc;     //该block的描述
  
  //block如果捕获了一些变量,则会添加到这里
  
  //C++中可以往struct中增加构造函数
  __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;
  }
};

//静态全局函数, 函数参数就是__main_block_impl_0本身的指针。和C++和OC中调用对象成员函数类似,第一参数都是this(self)
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
     printf("Block\n");
}

//静态全局结构体
static struct __main_block_desc_0 {
  size_t reserved;          //保留区域,以后版本升级可能会用到
  size_t Block_size;        //本block大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main(int argc, const char * argv[]) {
    //由于括号嵌套较多,我这里采取特殊的换行和空格格式,旨在看清楚括号嵌套背后的实际语法。


    //block表达式转换
    void (*blk)(void) = (
    (void (*)())                            //强制转换成 void (*)(void) 类型的函数指针
    &                                       //取地址,记录该栈对象的地址
    __main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)     //调用struct构造函数生成该block结构体实例
    
    );
    
    //上述的blk的类型暂时转换成了 void (*)(void),但其实它应该是一个 struct __main_block_impl_0* 类型
    //由于下列的调用中还要对其进行强制转换,所以上述转成什么类型,其实无关紧要。只要把该指针记录下来就行。
    
    //block调用
    (   
        (void (*)(__block_impl *))      //将函数指针强制转换成 void (*)(__block_impl *) 类型的函数指针
        ((__block_impl *)blk)->FuncPtr  //先将 blk 强制转成 __block_impl* 类型,再取其成员变量FuncPtr。则得到一个 void * 类型的变量
    )
    ((__block_impl *)blk)   //调用参数,即将 blk 强制转成 __block_impl* 类型
    ;              
    return 0;
}
  • I have inserted relevant detailed comments in the above source code, and removed the effect of nesting of parentheses by newlines and spaces. I believe it is easier to understand.

  • There is a point of knowledge that the pointer is forced to turn, and science is needed. (About the forced transfer of the blk type in the main function)

  • Pay attention to the naming rules of the structure

    • The author of "OC Advanced Programming" said: The name of the function to which the Block grammar belongs (main here) and the order value of the Block grammar appearing in the function (here 0) to name the function transformed by clang.

to sum up

  • The block declared by the programmer, the compiler will generate the corresponding Objective-C object (essentially a structure, because of the isa pointer, which matches the definition of the Objective-C object, so it is an Objective-C object).
  • This object type records the function pointer corresponding to the block and stores the variables captured by the block. Therefore, when the block is subsequently called, the function pointer recorded by the Objective-C object is actually called, and the parameters (the pointer of the block object itself, the variable captured by the block) are passed.

References

Guess you like

Origin www.cnblogs.com/HelloGreen/p/12684721.html