1.Block簡介:
可以簡單的理解岸浑,Block其實包含兩個部分內容:
1)Block執(zhí)行的代碼麻昼,這是在編譯的時候已經生成好的;
2)一個包含Block執(zhí)行時需要的所有外部變量值的數(shù)據(jù)結構。 Block將使用到的抽活、作用域附近到的變量的值建立一份快照拷貝到棧
P.S. Block與函數(shù)的區(qū)別:
Block可以訪問函數(shù)以外、詞法作用域以內的外部變量的值锰什。換句話說下硕,Block不僅 實現(xiàn)函數(shù)的功能,還能攜帶函數(shù)的執(zhí)行環(huán)境
2.Block的基本用法:
// 聲明一個Block變量
long (^sum) (int, int) = nil;// sum是個Block變量汁胆,該Block類型有兩個int型參數(shù)梭姓,返回類型是long。
// 定義Block并賦給變量
sumsum = ^ long (int a, int b) { return a + b;};
// 調用Block:
long s = sum(1, 2);
為了看著比較順眼,通常使用typedef進行定義
typedef long (^block)(int, int);
- (block) sumBlock {
int base = 100;
block blk = ^ long (int a, int b) {
return base + a + b;
}
return [[blk copy] autorelease];}
Block在內存中的位置
根據(jù)Block在內存中的位置分為三種類型NSGlobalBlock嫩码,NSStackBlock, NSMallocBlock誉尖。
NSGlobalBlock:類似函數(shù),位于text段铸题;
NSStackBlock:位于棧內存铡恕,函數(shù)返回后Block將無效;
NSMallocBlock:位于堆內存丢间。
block blk1 = ^ long (int a, int b) { return a + b;};
NSLog(@"blk1 = %@", blk1);// blk1 = <__NSGlobalBlock__: 0x47d0>
int base = 100;
block blk2 = ^ long (int a, int b) { return base + a + b;};
NSLog(@"blk2 = %@", blk2); // blk2 = <__NSStackBlock__: 0xbfffddf8>BlkSum
blk3 = [[blk2 copy] autorelease];
NSLog(@"blk3 = %@", blk3); // blk3 = <__NSMallocBlock__: 0x902fda0>
blk1與blk2的區(qū)別在于:
blk1沒有使用block外的任何外部變量,Block不需要建立局部變量值的快照,這就使得blk1與函數(shù)沒有任何的區(qū)別
blk2使用了外部的變量base,在定義(注意是定義探熔,不是運行)blk2時,局部變量base當前值被copy到棧上烘挫,作為常量供Block使用
例:
int base = 100;
base += 100;
block sum = ^ long (int a, int b) {
return base + a + b;
};
base++;
printf("%ld",sum(1,2));
打印結果為:203
在Block內變量base是只讀的诀艰,如果想在Block內改變base的值,在定義base時要用:__block int base = 100;
__block int base = 100;
base += 100;
BlkSum sum = ^ long (int a, int b) {
base += 10;
return base + a + b;
};
base++;
printf("%ld\n",sum(1,2));
printf("%d\n",base);
打印結果為:214和211
Block中使用__block修飾的變量時,將取變量此刻運行時的值涡驮,而不是定義時的快照
Block的copy暗甥、retain、release操作
不同于NSObjec的copy捉捅、retain撤防、release操作:
Block_copy與copy等效,Block_release與release等效棒口;
對Block不管是retain寄月、copy、release都不會改變引用計數(shù)retainCount无牵,retainCount始終是1漾肮;
1)NSGlobalBlock:retain、copy茎毁、release操作都無效克懊;
2)NSStackBlock:retain、release操作無效七蜘,必須注意的是谭溉,NSStackBlock在函數(shù)返回后,Block內存將被回收橡卤。即使retain也沒用扮念。容易犯的錯誤是[[mutableAarry addObject:stackBlock],在函數(shù)出棧后碧库,從mutableAarry中取到的stackBlock已經被回收柜与,變成了野指針。正確的做法是先將stackBlock copy到堆上嵌灰,然后加入數(shù)組:[mutableAarry addObject:[[stackBlock copy] autorelease]]弄匕。支持copy,copy之后生成新的NSMallocBlock類型對象伞鲫。
3)NSMallocBlock支持retain粘茄、release签舞,雖然retainCount始終是1秕脓,但內存管理器中仍然會增加、減少計數(shù)儒搭。copy之后不會生成新的對象吠架,只是增加了一次引用,類似retain搂鲫;
P.S盡量不要對Block使用retain操作傍药。
Block對不同類型的變量的存取
基本類型
局部自動變量,在Block中只讀。Block定義時copy變量的值拐辽,在Block中作為常量使用拣挪,所以即使變量的值在Block外改變,也不影響他在Block中的值俱诸。
static變量菠劝、全局變量。如果把上個例子的base改成全局的睁搭、或static赶诊。Block就可以對他進行讀寫了。因為全局變量或靜態(tài)變量在內存中的地址是固定的园骆,Block在讀取該變量值的時候是直接從其所在內存讀出舔痪,獲取到的是最新值,而不是在定義時copy的常量锌唾。
Block變量锄码,被__block修飾的變量稱作Block變量。 基本類型的Block變量等效于全局變量晌涕、或靜態(tài)變量巍耗。
Block被另一個Block使用時,另一個Block被copy到堆上時渐排,被使用的Block也會被copy炬太。但作為參數(shù)的Block是不會發(fā)生copy的
本文具體參考:http://blog.csdn.net/wildfireli/article/details/21979955