美文网首页iOS DeveloperiOS开发技巧
Objective-C Block(闭包)实现

Objective-C Block(闭包)实现

作者: 尘絮缘12138 | 来源:发表于2015-12-27 12:52 被阅读351次

    Block的实质

    Block我想写OC的都不会陌生,在项目中我们经常会使用block作为数据处理后的回调,例如通知主线程UI更新等。Block的语法看上去很特别,但是它实际上是作为及普通的C源代码来处理的。含有Block的源代码转换为一般的C语言代码,之后作为C语言代码被编译。

    这里插句题外话,很多动态语言底层都是C或者C++,例如Python,ruby底层都是C,这两门语言里面也有block的概念,只不过在python里称为lambda。所以他们的实现方式是相似的。

    OK,回到正题。首先,我们通过clang -rewrite-objc filename(clang是编译指令) 将含有block的源文件转换为C源代码,OC源代码如下:

    int main() {
      //block实现
      void (^test)(void) = ^{
         printf("Hello World\n");
      };
    
      test();
    
      return 0;
    }
    

    代码很简单,只是打印一个字符串.但是转换后却又10000+的代码,但是和block相关的代码却在底部,只有几十行而已,我们来看下:

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

    <br />

      static void __main_block_func_0(struct __main_block_impl_0 *__cself){
          printf("Hello World!\n");
      }
    

    <br />

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

    <br />

       int main() {
       void (*test)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0,       
        &__main_block_desc_0_DATA);
      ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)
      ((__block_impl *)test);
    
      return 0;
    }
    

    上面四段代码就是一个简单Block的C版本,下面我们一一讲解下。

      static void __main_block_func_0(struct __main_block_impl_0 *__cself){
        printf("Hello World!\n");
      }
    

    这段代码代表的就是block的实现,其中__main_block_func_0代表的是主函数中第0个函数,其参数是Block本身,类似C++的this指针和OC的self.

    下面我们来看看cself的类型:__main_block_impl_0

      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, intflags=0){
              impl.isa = &_NSConcreteStackBlock;
              impl.Flags = flags;
              impl.FuncPtr = fp;
              Desc = desc;
       }
      };
    

    可以看到这个类型是个结构体,里面有两个结构体参数,外加一个构造方法.其中变量impl是另一个结构体,我们来看下它的内容:

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

    除了耳熟能详的的isa指针外,我们还看到flags,估计是某些标志;reserved,升级预留区域,以及一个函数指针.

    再看看Desc的结构:

    struct __main_block_desc_0{
    unsigned long reserved;
    unsigned long Block_size;
    }
    

    代表的是版本升级预留区域,和block大小.

    下面我们看看其构造函数的调用:

      void (*test)(void) = (void (*)())&__main_block_impl_0((void
        *)__main_block_func_0, &__main_block_desc_0_DATA);  
      }
    

    其实就是将__main_block_impl_0结构体赋值给test变量,顺带初始化其他属性.
    之后,调用:

      ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)
       ((__block_impl *)test);  
      }
    

    这其实就是一个简单的函数指针调用函数,类似(*name)(paramters..)调用.

    致此,block的实质就讲的差不多了,漏了一个_NSConcreteStackBlock下次再讲吧.

    相关文章

      网友评论

        本文标题:Objective-C Block(闭包)实现

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