block源码
如图所示一个正常block底层被编译成了 __main_block_impl_0布局体,该布局体里包罗 _block_impl内里存储的是block的调用信息,__main_block_desc_0表现的是block内存描述。
剩下的属性即为block里引用到的属性
typedef void (^Block)(void);Block block;{ int val = 0; block = ^(){ NSLog(@"val = %d",val); };}block();///底层被编译成以下4个布局体struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr;};struct __main_block_impl_0 { ///block对象 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;}};struct void __main_block_func_0(struct __main_block_impl_0 *__cself){ printf("Block\n");}static struct __main_block_desc_0{ unsigned long reserved; unsigned long Block_size;} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};一共是四个布局体,一个block对象被编译为了一个__main_block_impl_0范例的布局体。这个布局体由两个成员布局体和一个构造函数构成。两个布局体分别是__block_impl和__main_block_desc_0范例的。此中__block_impl布局体中有一个函数指针,指针将指向__main_block_func_0范例的布局体。总结了一副关系图
为何block不能修改auto变量的值
当block必要截获自动变量的时间,起首会在__main_block_impl_0布局体中增长一个成员变量而且在布局体的构造函数中对变量赋值。以上这些对应着block对象的界说。
在block被实验的时间,把__main_block_impl_0布局体,也就是block对象作为参数传入__main_block_func_0布局体中,取出此中的val的值,进行接下来的操纵
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0 *Desc;
int val;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc,int _val, int flags=0) : val(_val){
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct void __main_block_func_0(struct __main_block_impl_0 *__cself){
int val = __cself->val;
printf("val = %d",val);
}
加粗部分我明白是他是对改属性进行了引用因此如果改变的话无法让外部的auto变量见效
怎样让block可以修改auto变量的值
加__block修饰,
编译器会将__block变量包装成一个布局体__Block_byref_age_0,布局体内部*__forwarding是指向自身的指针,内部还存储着外部auto变量的值
__block的forwarding指针如下图:
__block的源码被编译成了一个 ** __Block_byref_val_0**布局体,当block在栈上的时间他的fowarding指针指向他本身,如果block被拷贝到堆里的时间他的指针会指向堆区block的指针,堆区block的fowarding指针也指向他本身因此就能包管
struct __Block_byref_val_0 {
void *__isa;
__Block_byref_val_0 *forwarding;
int __flags;
int __size;
int val;
};
struct __Block_byref_val_0 { void *__isa; __Block_byref_val_0 *forwarding; int __flags; int __size; int val;};struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0 *Desc; __Block_byref_val_0 *val; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc,__Block_byref_val_0 *_val, int flags=0) : val(_val->__forwrding){ impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc;}};struct void __main_block_func_0(struct __main_block_impl_0 *__cself){ __Block_byref_val_0 *val = __cself->val; printf("val = %d",val->__forwarding->val);} |