美文网首页
iOS--Block

iOS--Block

作者: ihuangyg | 来源:发表于2016-09-11 10:21 被阅读0次

    先定个小目标,例如整理一篇关于 block 的笔记

    • 先用 OC 写一段最简单的 block 代码:

      int main(int argc, const char * argv[]) {
          @autoreleasepool {
              void (^myBlock)(void) = ^{
                  NSLog(@"hello world");
              } ;
              myBlock() ;
          }
          return 0;
      }
      
    • 使用 clang -rewrite-objc 查看 block 的源代码:

    ```objc
    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
         
            void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)) ;
            
            ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock) ;
        }
        return 0;
    }
    ```
    
    • 为了提高上述代码的可读性,将类型转化的代码去掉,变成如下代码:

      int main(){
          (*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ;
          myBlock -> FuncPtr ;
      }
      
      
    • 现在让我们来看下这两句代码的作用到底是什么

      首先我们发现,我们源代码中代码块里面的代码 “不见了”。在转化后的代码中,我们没有找到代码块里面的。

      ^{
          NSLog(@"hello world");
       } ;
      
    • 我们先看 __mian_block_func_0 这个参数到底是什么。查看 main.cpp 代码可以发现原来它是个方法,参数为 self (代码块):

      static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
              NSLog((NSString*)&__NSConstantStringImpl__var_folders_v4_lj0qxzgx4bn62svsmmv5gk240000gn_T_main_cc2878_mi_0);
      }
      
    • 由此我们可以知道我们代码块的内容都保存在 __mian_block_func_0 这个方法里面。然后作为参数传递到 __main_block_impl_0 这个方法里面。那么 __main_block_impl_0 这个方法又有什么作用呢?查看 mian.cpp 代码可以发现:

      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 impl

      该代码申明了一个 block 。__block_impl 的具体内容如下所示,可以看出 block 其实就是个结构体:

      struct __block_impl {
        void *isa;        //  指向对象该 block 的类型
        int Flags;        //  该 block 的一些其他信息
        int Reserved;     //  保留区
        void *FuncPtr;    //  该 block 指向的内存地址
      };
      

      struct __main_block_desc_0* Desc;

      该代码申明了一个关于该 block 的一些信息的方法。其实现如下所示:

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

      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0)

      该方法为 __main_block_impl_0 的构造函数,主要为 __block_impl 类型创建的 block 赋值。

      • fp 指向前面所述的__mian_block_func_0 的地址
      • desc 指向掐面所述的 __main_block_desc_0
      • flag...
    1. 综上所述,我们应该能够明白下面代码的作用了,就是将创建一个 block,初始化该结构体,在构造函数中传入自身(self) __main_block_func_0 结构体和基本信息。

      (*myBlock) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA) ;
      
    2. 得到新创建的 block 后,当我们调用原本代码的 block时候,就相当于调用:

      myBlock -> FunPtr
      

    参考资料

    相关文章

      网友评论

          本文标题:iOS--Block

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