block的实现原理(二)

来源:互联网 发布:怎么让4g网络信号增强 编辑:程序博客网 时间:2024/05/16 04:31

 OC代码: 

int a=10;

  void (^blk)(void) = ^(){

printf("This is a block.");

};

    

上面的OC代码被转化成了C语言的代码后,可以看出:block被转化成了指向__main_block_impl_0结构体的指针。这个结构体包含两个__block_impl__main_block_desc_0两个结构体,和一个方法。

    struct__main_block_impl_0 {

        struct __block_impl impl;

        struct __main_block_desc_0* Desc;

              int a;

   //下面这个是结构体构造函数 ,用来初始化变量__block_impl impl__main_block_desc_0    

__main_block_impl_0(void *fp,struct __main_block_desc_0 *desc,int _a, int flags=0):a(_a) {

            impl.isa = &_NSConcreteStackBlock;

            impl.Flags = flags;

            impl.FuncPtr = fp;

            Desc = desc;

                  }

    };



OC被转化成了以下C语言代码:

int a=10;

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


简化的C语言代码:

   void (*blk)(void) = &__main_block_impl_0(

     (void *)__main_block_func_0

      &__main_block_desc_0_DATA

);

   

//__main_block_impl_0 函数 参数:参数1 __main_block_func_0指针参数2 __main_block_desc_0_DATA :描述结构体大小 参数就是block之外的变量 a


//__main_block_func_0函数,即block对应的函数体。该函数接受一个__cself参数,即对应的block自身。

static void__main_block_func_0(struct __main_block_impl_0 *__cself) {

int a=__cself->a;

        printf("This is a block.");

    }


   

 struct __block_impl {

       void *isa;//isa指针,如果我们对runtime了解的话,就明白isa指向Class的指针  (_NSConcreteStackBlock,_NSConcreteMallocBlock_NSConcreteGlobalBlock)


   int Flags;//Flags,当block被copy时,应该执行的操作

   int Reserved;//Reserved为保留字段

   void *FuncPtr;//FuncPtr指针,指向block内的函数实现

    };



    staticstruct __main_block_desc_0 {

        size_t reserved;//reserved为保留字段默认为0

        size_t Block_size;//Block_size为sizeof(struct __main_block_impl_0),用来表示block所占内存大小。因为没有持有变量,block大小为impl的大小加上Desc指针大小

    } __main_block_desc_0_DATA = {0, sizeof(struct __main_block_impl_0)};

//__main_block_desc_0_DATA为__main_block_desc_0的一个结构体实例
这个结构体,用来描述block的大小等信息。如果持有可修改的捕获变量时(即加__block),会增加两个函数(copy和dispose)



OC代码:

blk();

转成C语言:

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

简化的C语言代码:

blk->FuncPtr(blk);block的创建和调用,可以看出执行block就是调用一个以block自身作为参数的函数,这个函数对应着block的执行体


//如果一个block外部的变量加了 __block修饰系统就会创建一个结构体内部封装了变量的地址

    

    __blockint a = 10;


    //结构体__Block_byref_a_0的变量

    struct __Block_byref_a_0 {

        void *__isa;

        __Block_byref_a_0 *__forwarding;//保存自己的地址,____forwarding,指向自己的指针,当从栈copy到堆时,指向堆上的block

        int __flags;// 0

        int __size; //当前结构体的大小

        int a;

    };

    __attribute__((__blocks__(byref)))__Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a,0, sizeof(__Block_byref_a_0),10};




block的类型用_NSConcreteStackBlock来表示,表明这个block位于栈中。同样地,还有_NSConcreteMallocBlock_NSConcreteGlobalBlock

由于block也是NSObject,我们可以对其进行retain操作。不过在将block作为回调函数传递给底层框架时,底层框架需要对其copy一份。比方说,如果将回调block作为属性,不能用retain,而要用copy。我们通常会将block写在栈中,而需要回调时,往往回调block已经不在栈中了,使用copy属性可以将block放到堆中。或者使用Block_copy()和Block_release()。



0 0
原创粉丝点击