Block實現-block的實質

Block的實質:函數

#import <Foundation/Foundation.h>
int main() {
    void(^blk)(void)=^{printf("Block");};
    blk();
    return 0;
}

使用clang將該block轉換。spa

clang -rewrite-objc  源代碼文件

轉換後造成的block文件是:指針

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

 

 
 

struct __main_block_impl_0 {code

 
 

  struct __block_impl impl;對象

 
 

  struct __main_block_desc_0* Desc;blog

 
 

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

 
 

    impl.isa = &_NSConcreteStackBlock;io

 
 

    impl.Flags = flags;class

 
 

    impl.FuncPtr = fp;import

 
 

    Desc = desc;

 
 

  }

 
 

};

 
 

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

 
 

printf("Block");}

 
 

 

 
 

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

 
 

int main() {

 
 

    void(*blk)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

 
 

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

 
 

    return 0;

 
 

}



下面咱們就來具體分析一下這些源代碼:

首先咱們看到

^{printf("Block");};

轉換後稱爲

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("Block");}

如上所示的,block使用的匿名函數,其實被轉換成c語言函數處理,,該函數中 的_cself是_main_block_func_0結構體的指針。

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;

具備兩個成員變量,_block_impld 代碼以下:

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

第二個成員變量是

__main_block_desc_0:其代碼以下:

 
 

static struct __main_block_desc_0 {

  size_t reserved;

  size_t Block_size;

}

 

這個包含了從此版本升級所需的區域以及block的大小。

下面咱們來看一下初始化含有這些數據的結構體的代碼:

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

在這裏面NSConcreteStackBlock用來初始化,接下來咱們對構造函數的調用:

 void(*blk)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

由於轉換太多實在太難以理解,因此咱們去掉轉換的部分,這樣獲得的結果是:

struct _main_block_impl_0 tmp=_main_block_impl_0(_main_block_func_0,&_main_block_desc_DATA);
struct _main_block_impl_0  *blk=&tmp;

這樣一來咱們能夠清楚的看到,

void(^blk)(void)=^{printf("Block");};

這個語句的實現了_main_block_impl_0的兩個變量,一個功能函數,一個desc,將block語法生成的block類型對象再賦值給blk,至關於將實例的指針賦值給blk,_main_block_desc_DATA主要是對_main_block_impl_0的結構體實例的大小進行初始化.

blk();

這部分代碼轉換成爲了

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

咱們同樣去掉轉換的部分獲得:

(*blk)->impl.Funcptr(blk)

這實際上是最簡單的函數指針調用函數,正如咱們剛纔確認的那樣,在調用函數中咱們看出block是做爲參數進行傳遞的。

那麼到底什麼是NSConcreteStackBlock呢?

爲了理解他首先咱們須要理解oc類和對象的實質,其實,所謂的block就是對象,「id」這一變量用於存儲oc對象,NSConcreteStackBlock就至關於c結構體實例,將block做爲oc對象處理時,該類的信息就放置於NSConcreteStackBlock處。

相關文章
相關標籤/搜索