Block是C語音級別和運行時放面的一個特征。Block封裝了一段代碼邏輯,也用{}括起,和標準C語音中的函數(shù)/函數(shù)指針很相似,此外就是block能夠對定義環(huán)境中的變量可引用到。這一點和"閉包"概念類似。
block有很多應用場景,如對代碼封裝作為參數(shù)傳遞。這在使用dispatch并發(fā)(Operation中也有BlockOperation)和completion異步回調等處都廣泛應用。
1.Block的基本使用
聲明: (返回類型)(^聲明的block名稱)(參數(shù)列表);
實現(xiàn): ^(參數(shù)列表){代碼塊}
建議出現(xiàn)多次的block使用typedef定義。
block的調用: ? block名稱(參數(shù)列表);
2.使用中的注意點
(1)對定義環(huán)境的變量使用。默認是以const的方式使用,這有點像函數(shù)的const參數(shù)傳遞,如過需要block內(nèi)修改可變,則使用__block,這樣做存儲就實現(xiàn)了共享,包括塊中的遞歸應用和定義環(huán)境上下文中的多個block使用。block通常定義在棧幀當中,而當所處的棧幀被銷毀的時候,block以及引用到的__block變量將會依然有效。
(2)引用類型問題。block中的引用默認都是強引用,必要的時候需要使用__weak,同delegate使用的注意一樣,避免循環(huán)引用。此外,蘋果文檔中還給出了對instanceVariable和對localVariable引用不同的例子,注意體會下。
(3)copy。在類屬性中,要使用copy。此外,對block進行copy要使用Block_copy()/Block_release()。
3.聯(lián)想Java中匿名類使用
Java7以及之前的各個版本中,沒有“閉包”的概念(感興趣的可以看今年3月Oracle發(fā)布的Java8),回調(callback)使用內(nèi)部類實現(xiàn)。在方法定義中使用匿名內(nèi)部類,需要注意的一點是匿名類中對外部方法參數(shù)的使用,要求參數(shù)只能是final的。
其實在iOS中,對于block使用外部方法的參數(shù),也只能是const的,不能對參數(shù)進行__block要求。
4.Block與對象的關系
Block是OC語言中的對象。Block對象與一般的類實例對象有所不同,一個主要的區(qū)別就是分配的位置不同,block默認在棧上分配,一般類的實例對象在堆上分配。
retain是對一個在堆中分配內(nèi)存的對象的引用計數(shù)做了增加,執(zhí)行release操作的時候檢查計數(shù)是否為1,如果是則釋放堆中內(nèi)存。而對于在棧上分配的block對象,這一點顯然有所不同,如果方法調用返回,棧幀上的數(shù)據(jù)自然會作廢處理,不像堆上內(nèi)存,需要單獨release,就算NSArray對block對象本身做了retain也無濟于事。
用一個方法對block數(shù)組做初始化是否有可能方案呢。答案是肯定的,不過需要真正了解block的使用,至少要會用Block_copy()和Block_release()。
5.Block的類型和使用
NSGlobalBlock 顯示的是沒有對周圍變量沒有引用的Block。
NSStackBlock 是其中加入了對定義環(huán)境變量的引用。
NSMallockBlock ?對一個NSStackBlock對象使用了Block_copy()或者發(fā)送了copy消息,就會得到NSMallocBlock。
對于Global的Block,我們無需多處理,不需retain和copy,因為即使你這樣做了,似乎也不會有什么兩樣。對于Stack的Block,如果不做任何操作,就會向上面所說,隨棧幀自生自滅。而如果想讓它獲得比stack frame更久,那就調用Block_copy(),讓它搬家到堆內(nèi)存上。而對于已經(jīng)在堆上的block,也不要指望通過copy進行“真正的copy”,因為其引用到的變量仍然會是同一份,在這個意義上看,這里的copy和retain的作用已經(jīng)非常類似
在類中,如果有block對象作為property,可以聲明為copy。
參考:http://www.molotang.com/articles/1691.html