block变量

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

block变量上一篇讲的是block静态变量的特性,这里我们来看一下_block变量。引用官方:

You can specify that an imported variable be mutable—that is, read-write— by applying the __block storage type modifier. __blockstorage is similar to, but mutually exclusive of, the register, auto, and static storage types for local variables.

通过指定__block存储类型修饰符,可以读写。__block存储是类似的,但相互排斥的,寄存器,自动变量,和局部变量和静态变量类型(后面这句不太理解)。

我们来写个例子,用__block修饰局部变量(对于全局变量是无效的,没有任何作用,全局变量成员变量本身就可以在block内部修改,详细看这一篇):

voidmain1()

{

__blockchar*_para1="a";PRintf("init _para1:%s,%p,%p\n",_para1,_para1,&_para1);void(^testBlock)(void)=^{

printf("exute _para1:%s,%p,%p\n",_para1,_para1,&_para1);

};

_para1="b";

printf("before _para1:%s,%p,%p\n",_para1,_para1,&_para1);

testBlock();

printf("after _para1:%s,%p,%p\n",_para1,_para1,&_para1);

}

执行后输出如下:

init _para1:a,0x47f4,0xbfffc9c0

before _para1:b,0x4829,0x8da4580

exute _para1:b,0x4829,0x8da4580

after _para1:b,0x4829,0x8da4580

这里加了__block修饰符。通过日志可以看出,block内部_para1的地址、值和执行前的_para1一样,在block初始化后,对变量_para1的修改,可以同步到block内,block内并不是截获了变量的值。我们可以看下通过clang 转换后的后的cpp代码:

//block 的实现函数的对象

struct__block_impl {void*isa;intFlags;intReserved;void*FuncPtr;

};

//block 引用的参数对象(每一个参数生成一个结构体)

struct__Block_byref__para1_0 {void*__isa;

__Block_byref__para1_0*__forwarding;int__flags;int__size;char*_para1;

};

//block对象

struct__main1_block_impl_0 {struct__block_impl impl;struct__main1_block_desc_0*Desc;

__Block_byref__para1_0*_para1;//by ref__main1_block_impl_0(void*fp,struct__main1_block_desc_0 *desc, __Block_byref__para1_0 *__para1,intflags=0) : _para1(__para1->__forwarding) {

impl.isa= &_NSConcreteStackBlock;

impl.Flags=flags;

impl.FuncPtr=fp;

Desc=desc;

}

};

//block 的实现

staticvoid__main1_block_func_0(struct__main1_block_impl_0 *__cself) {

__Block_byref__para1_0*_para1 = __cself->_para1;//bound by refprintf("exute _para1:%s,%p,%p\n",(_para1->__forwarding->_para1),(_para1->__forwarding->_para1),&(_para1->__forwarding->_para1));

}

//其他函数(copy、dispose:为了管理_Block_byref__para1_0 结构体变量的内存)

staticvoid__main1_block_copy_0(struct__main1_block_impl_0*dst,struct__main1_block_impl_0*src) {_Block_object_assign((void*)&dst->_para1, (void*)src->_para1,8/*BLOCK_FIELD_IS_BYREF*/);}staticvoid__main1_block_dispose_0(struct__main1_block_impl_0*src) {_Block_object_dispose((void*)src->_para1,8/*BLOCK_FIELD_IS_BYREF*/);}staticstruct__main1_block_desc_0 {

size_t reserved;

size_t Block_size;void(*copy)(struct__main1_block_impl_0*,struct__main1_block_impl_0*);void(*dispose)(struct__main1_block_impl_0*);

} __main1_block_desc_0_DATA= {0,sizeof(struct__main1_block_impl_0), __main1_block_copy_0, __main1_block_dispose_0};

//这是我们的测试函数

voidmain1()

{

__attribute__((__blocks__(byref))) __Block_byref__para1_0 _para1= {(void*)0,(__Block_byref__para1_0 *)&_para1,0,sizeof(__Block_byref__para1_0),"a"};

printf("init _para1:%s,%p,%p\n",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));void(*testBlock)(void)=(void(*)())&__main1_block_impl_0((void*)__main1_block_func_0, &__main1_block_desc_0_DATA, (__Block_byref__para1_0 *)&_para1,570425344);

(_para1.__forwarding->_para1)="b";

printf("before _para1:%s,%p,%p\n",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));

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

printf("after _para1:%s,%p,%p\n",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));

}

发现和不加__block不太一样,多了一个结构体(_Block_byref__para1_0)

struct__Block_byref__para1_0 {void*__isa;

__Block_byref__para1_0*__forwarding;int__flags;int__size;char*_para1;

};

这个结构体就是用__block 声明的变量,声明__block变量_para1 转换后的代码如下:

__attribute__((__blocks__(byref))) __Block_byref__para1_0 _para1 = {(void*)0,(__Block_byref__para1_0 *)&_para1,0,sizeof(__Block_byref__para1_0),"a"};

其实就是生成一个_Block_byref__para1_0对象,__forwarding 指针指向变量结构体自己

void(*testBlock)(void)=(void(*)())&__main1_block_impl_0((void*)__main1_block_func_0, &__main1_block_desc_0_DATA, (__Block_byref__para1_0 *)&_para1,570425344);

初始化block,传递结构体变量_para1、函数地址、描述信息等参数,block对象的成员 _para1 引用了_para1结构体的地址,这样就可以修改_para1,而且外界对_para1结构体的修改都可以同步到block对象的成员_para1中,修改代码如下:

(_para1.__forwarding->_para1)="b";

直接通过__Block_byref__para1_0结构体的成员__forwarding(指向自己)取得_para1成员的地址,然后就可以读写,达到了修改变量的目的。

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

执行block,依然是通过调用函数指针 FuncPtr实现,并传递block自身。函数体代码如下:

staticvoid__main1_block_func_0(struct__main1_block_impl_0 *__cself) {

__Block_byref__para1_0*_para1 = __cself->_para1;//bound by refprintf("exute _para1:%s,%p,%p\n",(_para1->__forwarding->_para1),(_para1->__forwarding->_para1),&(_para1->__forwarding->_para1));

}

在函数体内,通过block对象的成员_para1(__Block_byref__para1_0)的指针,再通过自身的成员__forwarding指针来获取_para1。

我的理解就是指针引用的关系,不知道为什么要加一个__forwarding指针 ,直接去引用自身的成员 _para1难道不行吗?希望大神赐教。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航