Block截獲自動(dòng)變量的情況
</br>
Objective-C語句:
int main() {
int dmy = 256;
int val = 10;
const char *fmt = "val = %d\n";
void (^blk)(void) = ^{ printf(fmt, val); };
val = 2;
fmt = "These values were changed. val = %d\n";
blk();
return 0;
}
C++源碼:(注:有一部分與上例相同的代碼已省略)
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0 *Desc;
const char *fmt;
int val;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {
const char *fmt = __cself->fmt;
int val = __cself->val;
printf(fmt, val);
}
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)
};
int main() {
int dmy = 256;
int val = 10;
const char *fmt = "val = %d\n";
void (*blk)(void) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, fmt, val);
}
整體看削解,__main_block_impl_0
結(jié)構(gòu)體柱徙、__main_block_func_0
函數(shù)整以、和main
函數(shù)內(nèi)blk
對(duì)構(gòu)造函數(shù)的調(diào)用都發(fā)生了改變:
-
__main_block_impl_0
結(jié)構(gòu)體內(nèi)聲明的成員變量與自動(dòng)變量的類型完全相同const char *
和int
。同時(shí)發(fā)現(xiàn)很重要的一點(diǎn)棵帽,dmy
變量沒有被追加到__main_block_impl_0
結(jié)構(gòu)體的成員變量中通铲。為什么?因?yàn)锽lock沒有使用它片任。由此得知偏友,Block對(duì)自動(dòng)變量的截獲只針對(duì)會(huì)在Block內(nèi)使用的自動(dòng)變量。 同時(shí)对供,該結(jié)構(gòu)體的構(gòu)造函數(shù)也對(duì)截獲的自動(dòng)變量追加的成員變量進(jìn)行了初始化操作位他。
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) { ... }
-
main
函數(shù)內(nèi)的構(gòu)造函數(shù)調(diào)用中也添加了相應(yīng)的參數(shù)
void (*blk)(void) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, fmt, val)
-
__main_block_func_0
函數(shù)
static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {
const char *fmt = __cself->fmt;
int val = __cself->val;
printf(fmt, val);
}
由于在main
中blk
調(diào)用構(gòu)造函數(shù)時(shí)已經(jīng)截獲到自動(dòng)變量,并被保存到Block結(jié)構(gòu)體的實(shí)例中产场,所以可以直接使用__cself->fmt
和__cself->val
鹅髓。
至此,可以解釋兩件事情:
第一京景,為什么在Block截獲了自動(dòng)變量之后窿冯,在外部修改自動(dòng)變量的值,不會(huì)影響B(tài)lock截獲到的值醋粟。
答:見代碼注釋部分的文字靡菇。
int dmy = 256;
int val = 10;
const char *fmt = "val = %d\n";
void (^blk)(void) = ^{ printf(fmt, val); }; //此處完成自動(dòng)變量的截獲
val = 2; //在Block外修改自動(dòng)變量的值重归,不會(huì)影響B(tài)lock內(nèi)已經(jīng)保存的值
fmt = "These values were changed. val = %d\n";
blk();
第二,為什么Block截獲的自動(dòng)變量不能被改寫厦凤。
答:因?yàn)樵趯?shí)現(xiàn)上不能改寫被截獲自動(dòng)變量的值鼻吮。
int val = 0;
void (^blk)(void) = ^{ val = 1; };
我們知道賦值語句^{ val = 1; }
實(shí)際上是在調(diào)用Block的構(gòu)造函數(shù),但是在實(shí)現(xiàn)構(gòu)造函數(shù)中并沒有參數(shù)位置可以保存這個(gè)要賦值給val
的1
较鼓。對(duì)于這種行為椎木,編譯器在編譯過程會(huì)檢測(cè)出,從而產(chǎn)生編譯錯(cuò)誤博烂。