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類型的結構體尸昧。這個結構體由兩個成員結構體和一個構造函數(shù)組成偎行。兩個結構體分別是__block_impl和__main_block_desc_0類型的枉层。其中__block_impl結構體中有一個函數(shù)指針,指針將指向__main_block_func_0類型的結構體届宠∷嘎洌總結了一副關系圖
為何block不能修改auto變量的值
當block需要截獲自動變量的時候乘粒,首先會在__main_block_impl_0結構體中增加一個成員變量并且在結構體的構造函數(shù)中對變量賦值。以上這些對應著block對象的定義伤塌。
在block被執(zhí)行的時候灯萍,把__main_block_impl_0結構體,也就是block對象作為參數(shù)傳入__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被拷貝到堆里的時候他的指針會指向堆區(qū)block的指針,堆區(qū)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);
}