X.4.1 變數(shù)的型態(tài)
我們可以在block中遇到平常在函數(shù)中會遇到的變數(shù)類型:
l 全域(global)變數(shù)或是靜態(tài)的區(qū)域變數(shù)(static local)。
l 全域的函數(shù)。
l 區(qū)域變數(shù)和由封閉領域(enclosing scope)傳入的參數(shù)。
除了上述之外block額外支援了另外兩種變數(shù):
在函數(shù)內可以使用__block 變數(shù),這些變數(shù)在block中是可被修改的。
匯入常數(shù)(const imports)。
此外,在方法的實作里,block可以使用Objective-C的實體變數(shù)(instance variable)。
下列的規(guī)則可以套用到在block中變數(shù)的使用:
可以存取全域變數(shù)和在同一領域(enclosing lexical scope)中的靜態(tài)變數(shù)。
可以存取傳入block的參數(shù)(使用方式和傳入函數(shù)的參數(shù)相同)。
在同一領域的區(qū)域變數(shù)在block中將視為常數(shù)(const)。
可以存取在同一領域中以__block 為修飾詞的變數(shù)。
在block中宣告的區(qū)域變數(shù),使用方式和平常函數(shù)使用區(qū)域變數(shù)的方式相同。
下面的例子介紹了區(qū)域變數(shù)(上述第三點)的使用方式:
1:intx = 123 ;
2:void(^printXAndY)(int) = ^(inty)
3:{
4:printf ("%d %d\n", x, y);
5:};
6:// 將會印出123 456
7:printXAndY( 456 );
8:就如上面第三點所提到的,在上例中的int x = 123的變量x,在傳入block后將視同常數(shù),因此若我們在block中試著去修改x的值時就會產生錯誤,下面的例子將會無法通過編譯:
9:
10:intx = 123 ;
11:void(^printXAndY)(int) = ^(inty)
12:{
13:// 下面這一行是錯的,因為x 在這是一個常數(shù)不能被修改。
14:x = x + y;
15:printf ("%d %d\n", x, y);
16:};
若在block中想要修改上面的變數(shù)x,必須將x宣告加上修飾詞__block,請參考接下來這一小節(jié)的介紹。
X.4.2 __block 型態(tài)變數(shù)
我們可以藉由將一個由外部匯入block的變數(shù)放上修飾詞__block來讓這個變數(shù)由唯讀變成可以讀和寫,不過有一個限制就是傳入的變數(shù)在記憶體中必須是一個占有固定長度記憶體的變數(shù),__block修飾詞無法使用于像是變動長度的陣列這類不定長度的變數(shù),請參考下面的范例:
1:// 加上__block 修飾詞,所以可以在block 中被修改。
2:__blockintx = 123 ;
3:void(^printXAndY)(int) = ^(inty)
4:{
5:x = x + y;
6:printf ("%d %d\n", x, y);
7:};
8:// 將會印出579 456
9:printXAndY( 456 );
10://x 將會變成 579;
11:下面我們使用一個范例來介紹各類型的變數(shù)和block之間的互動:
12:
13:externNSInteger CounterGlobal;
14:staticNSInteger CounterStatic;
15:{
16:NSInteger localCounter = 42 ;
17:__blockcharlocalCharacter;
18:void(^aBlock)(void) = ^(void)
19:{
20:++ CounterGlobal ;//可以存取。
21:++ CounterStatic ;//可以存取。
22:CounterGlobal = localCounter;//localCounter在block 建立時就不可變了。
23:localCharacter ='a';//設定外面定義的localCharacter 變數(shù)。
24:};
25:++localCounter;//不會影響的block 中的值。
26:localCharacter ='b';
27:aBlock();//執(zhí)行block 的內容。
28://執(zhí)行完后,localCharachter 會變成'a'
29:}
X.4.3 物件和Block變數(shù)
Block
支援在Objective-C、C++物件和其他block中當作變數(shù)來使用,不過因為在大部分的情況我們都是使用Objective-C的撰寫程式,因此在這一小節(jié)我們僅針對Objective-C的情況進行介紹,至于其他兩種情況就留給有興趣的讀者再自行深入研究了。
x.4.3.1 Objective-C 物件
在擁有參考計數(shù)(reference-counted)的環(huán)境中,若我們在block中參考到Objective-C的物件,在一般的情況下它將會自動增加物件的參考計數(shù),不過若以__block為修飾詞的物件,參考計數(shù)則是不受影響。
如果我們在Objective-C的方法中使用block時,以下幾個和記憶體管理的事是需要額外注意的:
l 若直接存取實體變數(shù)(instance variable),self的參考計數(shù)將被加1。
l 若透過變數(shù)存取實體變數(shù)的值,則只變數(shù)的參考計數(shù)將被加1。
以下程式碼說明上面兩種情況,在這個假設instanceVariable是實體變數(shù):
1:dispatch_async (queue, ^{
2:// 因為直接存取實體變數(shù)instanceVariable ,所以self 的retain count 會加1
3:doSomethingWithObject (instanceVariable);
4:});
5:id localVaribale = instanceVariable;
6:dispatch_async (queue, ^{
7://localVariable 是存取值,所以這時只有l(wèi)ocalVariable 的retain count 加1
8://self 的 return count 并不會增加。
9:doSomethingWithObject (localVaribale);
10:});