天天看點

Block的實作原理

Block的實作原理

這篇是記錄根據網上的文章進行的實際操作。C函數的生成中間編譯代碼的編譯方法是clang -rewrite-objc xxxx.c。由于編譯檔案中内容較多,這裡我們隻截取有關block的部分。

首先,看看沒有block的C函數以及編譯後的結果:

#include <stdio.h>

int main(){
    return ;
}
           

編譯代碼中的block:這裡我們可以看到一個block的C實作。

#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
           

*isa說明block也可以作為對象使用(例如我們定義一個myBlock類型的block1),指針變量FunPtr應該就是指向了block代碼塊的函數首位址

接着我們加一個block到.c檔案中,并進行編譯。

#include <stdio.h>

int main(){
int i = ;

void(^myBlock)(void) = ^(void){
    printf("hello world! %d\n",i);

};
myBlock();

return ;
}
           

編譯後:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int i;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _i, int flags=) : i(_i) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int i = __cself->i; // bound by copy

  printf("hello world! %d\n",i);

 }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { , sizeof(struct __main_block_impl_0)};
int main(){
 int i = ;

 void(*myBlock)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, i);

 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);

 return ;
}
           

3.假如我們要修改函數中局部變量的值,則需要加上__block修飾符,後面我們來看看為什麼這樣才可以修改。

#include <stdio.h>

int main(){
__block int i = ;

void(^myBlock)(void) = ^(void){
i = ;
    printf("hello world! %d\n",i);

};
myBlock();

return ;
}
           

編譯後的cpp代碼:

struct __Block_byref_i_0 {
  void *__isa;
__Block_byref_i_0 *__forwarding;
 int __flags;
 int __size;
 int i;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_i_0 *i; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_i_0 *_i, int flags=) : i(_i->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_i_0 *i = __cself->i; // bound by ref

  (i->__forwarding->i) = ;
  printf("hello world! %d\n",(i->__forwarding->i));

 }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->i, (void*)src->i, /*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->i, /*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { , sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(){
 __attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*),(__Block_byref_i_0 *)&i, , sizeof(__Block_byref_i_0), };

 void(*myBlock)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_i_0 *)&i, );

 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);

 return ;
}