ios4.0之后,block橫空出世,它本身封裝了一段代碼并將這段代碼當(dāng)做變量,通過block()的方式進(jìn)行回調(diào).類似于C函數(shù)中,定義一個(gè)指向函數(shù)的指針并調(diào)用:
bool executeSomeTask(void) {
// do something and return if success or not
}
bool (*taskPoint)(void);
taskPoint = something;
上面的函數(shù)指針可以直接通過(*taskPoint)()方式調(diào)用executeSomeTask這個(gè)函數(shù), 這樣對(duì)比block似乎跟C語言的函數(shù)指針是一樣的, 但是兩者仍然存在差別:
1. block的代碼是內(nèi)聯(lián)的, 效率高于函數(shù)調(diào)用;
2. block對(duì)于外部變量默認(rèn)是只讀屬性,要變成可讀可寫,就需要加上__block,或者將棧中的block復(fù)制到堆上一份,從而避免了循環(huán)引用這個(gè)情況;
3. block被Objective-C看成是對(duì)象處理
下面,我們一起來認(rèn)識(shí)一下神秘的Block:
首先了解洗block的三種存儲(chǔ)形態(tài):
_NSConcretStackBlock(棧),_NSConcretGlobalBlock(全局),_NSConcretMallocBlock(堆)
要點(diǎn)一: 當(dāng)block在函數(shù)內(nèi)部, 且定義的時(shí)候就使用了函數(shù)內(nèi)部的變量, 那么這個(gè)block是存儲(chǔ)在棧上的.
要點(diǎn)二: 1.當(dāng)block定義在函數(shù)體外面, 2.定義在函數(shù)體內(nèi)部,但當(dāng)時(shí)函數(shù)執(zhí)行的時(shí)候,block體中并沒有需要使用函數(shù)內(nèi)部的局部變量, 也就是block在函數(shù)執(zhí)行的時(shí)候只是靜靜地待在一邊定義了一下而不使用函數(shù)體的內(nèi)容, 那么block將會(huì)被編譯器存儲(chǔ)為全局block.
要點(diǎn)三: 全局block儲(chǔ)存在堆中, 對(duì)全局block使用copy操作會(huì)返回原函數(shù)指針;而對(duì)棧中的block使用copy操作,會(huì)產(chǎn)生兩個(gè)不同的block地址, 也就是了兩個(gè)匿名函數(shù)的入口地址.
要點(diǎn)四: ARC機(jī)制優(yōu)化會(huì)將stack的block, 轉(zhuǎn)為heap的block進(jìn)行調(diào)用.
Block的基本定義:
int (^myBlock)(int a, int b) = ^(int a, int b){ return a*b};
第一個(gè)int 為返回值類型,如果沒有返回值則用void
myBlock 為block 的名字
第二個(gè)int 為參數(shù)類型
等號(hào)前面為block的聲明,等號(hào)后面為block的實(shí)現(xiàn)
int a, int b 為block傳入的形參
大括號(hào)內(nèi)部為block體
block是代碼塊,所以需要用;符號(hào)
如果暫時(shí)等號(hào)左邊的值不需要的話,block是不執(zhí)行的
按照這種聲明方式未免麻煩了些,別擔(dān)心,蘋果早已為我們準(zhǔn)備好了一切
typedef void(^DownloadBlock)(NSData *success);
就是這么簡(jiǎn)單,然后可以自救寫一個(gè)屬性方便調(diào)用,或者嵌在函數(shù)里,或者直接調(diào)用
總結(jié):block捕獲變量,代碼傳遞,代碼內(nèi)聯(lián)等特性賦予了它多于代理機(jī)制的功能和靈活性,盡管它也存在循環(huán)引用,不易調(diào)試追溯等缺陷,但是無疑它深受開發(fā)者的喜愛.