前段時(shí)間心血來(lái)潮,研究了一下block底層實(shí)現(xiàn)脱茉,在網(wǎng)上看了好多文章垄开,基本都是通過(guò)clang 將代碼轉(zhuǎn)換為C++代碼去分析Blcok的實(shí)現(xiàn)。今天我們反過(guò)來(lái)思考榜田,用C去實(shí)現(xiàn)一個(gè)OC Block的效果箭券。
Block的實(shí)現(xiàn)本質(zhì)上是一些結(jié)構(gòu)體邦鲫,函數(shù)指針,函數(shù)屁魏,的綜合運(yùn)用氓拼。
話不多說(shuō)桃漾,直奔主題:
Block的實(shí)現(xiàn)拟逮,首先需要聲明一個(gè)結(jié)構(gòu)敦迄,這個(gè)結(jié)構(gòu)是我們實(shí)現(xiàn)Block的基礎(chǔ)恋追,也是關(guān)鍵
struct __block_impl {
void *isa;?
int Flags;
int Reserved;
void *FuncPtr;
};
說(shuō)明一下:
1.isa 保存的是Block的類型
2.Flags 當(dāng)block發(fā)生copy時(shí)罚屋,會(huì)用到
3.FuncPtr 指針苦囱,指向block內(nèi)的函數(shù)實(shí)現(xiàn)(后面函數(shù)指針調(diào)用的函數(shù))
這個(gè)結(jié)構(gòu)體脾猛,是所有類型的Block都會(huì)有的一部分撕彤。
然后我們看第二個(gè)結(jié)構(gòu)體
static struct __simpleblk_block_desc_0 {
size_t reserved;
size_t Block_size;
} __simpleblk_block_desc_0_DATA = {0,sizeof(struct __simpleblk_block_impl_0)};
說(shuō)明一下:
1.reserved 保留字段默認(rèn)是0
2.Block_size ?用來(lái)保存block所占內(nèi)存大小猛拴。
這個(gè)結(jié)構(gòu)體用來(lái)描述block的大小等信息羹铅,__simpleblk_block_desc_0_DATA是__simpleblk_block_desc_0的一個(gè)結(jié)構(gòu)體實(shí)例瞧柔。
我們?cè)倏吹谌齻€(gè)結(jié)構(gòu)體睦裳,也是Block實(shí)現(xiàn)最重要的結(jié)構(gòu)造锅,聲明如下:
struct __simpleblk_block_impl_0 {
struct __block_impl impl;
struct __simpleblk_block_desc_0 *Desc;
__simpleblk_block_impl_0(void *fp,struct __simpleblk_block_desc_0 *desc,int flags = 0){
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
說(shuō)明一下:
從這個(gè)結(jié)構(gòu)中可以看到哥蔚,該結(jié)構(gòu)體含有 __block_impl 結(jié)構(gòu)的變量 和 __simpleblk_block_desc_0 結(jié)構(gòu)的變量牵祟,以及結(jié)構(gòu)體構(gòu)造函數(shù)__simpleblk_block_impl_0深夯,結(jié)構(gòu)體構(gòu)造函數(shù)用來(lái)初始化變量__block_impl和__simpleblk_block_desc_0诺苹。
到這里收奔,我們實(shí)現(xiàn)最簡(jiǎn)單的Block所需要的結(jié)構(gòu)就聲明完了掌呜,但是要達(dá)到OC Block 那種效果,僅有結(jié)構(gòu)體 肯定是不夠的坪哄。截下來(lái)我們來(lái)看一個(gè)關(guān)鍵的函數(shù)质蕉,你沒(méi)猜錯(cuò)就是一個(gè)很簡(jiǎn)單的C函數(shù):
static void __simpleblk_block_func_0(struct __simpleblk_block_impl_0 *__cself) {
printf("this is charles's simple block!!");
}
這個(gè)函數(shù)其實(shí)就是我們的Block塊里面的操作。后面調(diào)用之后就會(huì)很清楚翩肌。
到這里我們就可以寫一個(gè)C函數(shù)來(lái)達(dá)到一個(gè)Block的效果:
int simpleblk(){
//聲明一個(gè)結(jié)構(gòu)體變量
__simpleblk_block_impl_0 __simpleblk_impl0 = __simpleblk_block_impl_0((void *)__simpleblk_block_func_0,&__simpleblk_block_desc_0_DATA);
//聲明一個(gè)函數(shù)指針變量block模暗,并且將上面的結(jié)構(gòu)體變量的地址付給block指針
void(*block)(void) = (void(*)())&__simpleblk_impl0;
/*
下面這句代碼 實(shí)際上調(diào)用的是 __simpleblk_block_func_0()函數(shù)
就是函數(shù)指針調(diào)用函數(shù)。
*/
((void (*)(struct __block_impl *))((struct __block_impl *)block)->FuncPtr)((struct __block_impl *)block);
return 1;
}
其實(shí)念祭,上面寫了這么多兑宇,換成OC代碼其實(shí)就是在一個(gè)函數(shù)里面,聲明了一個(gè)Block變量并且調(diào)用它棒卷。
int simpleblk() {
void (^block)(void) = ^(){
printf("this is charles's block!!");
};
block();
return 1;
}
到這里我們用C語(yǔ)言實(shí)現(xiàn)OC的 Block效果基本就寫完了顾孽,不知道各位看官是否看明白了呢。比规。(PS:歡迎大家勘誤若厚,共同學(xué)習(xí)!)