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