X.4.1 变数的型态
我们可以在block中遇到平常在函数中会遇到的变数类型:
l 全域(global)变数或是静态的区域变数(static local)。
l 全域的函数。
l 区域变数和由封闭领域(enclosing scope)传入的参数。
除了上述之外block额外支援了另外两种变数:
在函数内可以使用__block 变数,这些变数在block中是可被修改的。
汇入常数(const imports)。
此外,在方法的实作里,block可以使用Objective-C的实体变数(instance variable)。
下列的规则可以套用到在block中变数的使用:
可以存取全域变数和在同一领域(enclosing lexical scope)中的静态变数。
可以存取传入block的参数(使用方式和传入函数的参数相同)。
在同一领域的区域变数在block中将视为常数(const)。
可以存取在同一领域中以__block 为修饰词的变数。
在block中宣告的区域变数,使用方式和平常函数使用区域变数的方式相同。
下面的例子介绍了区域变数(上述第三点)的使用方式:
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后将视同常数,因此若我们在block中试着去修改x的值时就会产生错误,下面的例子将会无法通过编译:
9:
10:intx = 123 ;
11:void(^printXAndY)(int) = ^(inty)
12:{
13:// 下面这一行是错的,因为x 在这是一个常数不能被修改。
14:x = x + y;
15:printf ("%d %d\n", x, y);
16:};
若在block中想要修改上面的变数x,必须将x宣告加上修饰词__block,请参考接下来这一小节的介绍。
X.4.2 __block 型态变数
我们可以藉由将一个由外部汇入block的变数放上修饰词__block来让这个变数由唯读变成可以读和写,不过有一个限制就是传入的变数在记忆体中必须是一个占有固定长度记忆体的变数,__block修饰词无法使用于像是变动长度的阵列这类不定长度的变数,请参考下面的范例:
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:下面我们使用一个范例来介绍各类型的变数和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 变数。
24:};
25:++localCounter;//不会影响的block 中的值。
26:localCharacter ='b';
27:aBlock();//执行block 的内容。
28://执行完后,localCharachter 会变成'a'
29:}
X.4.3 物件和Block变数
Block
支援在Objective-C、C++物件和其他block中当作变数来使用,不过因为在大部分的情况我们都是使用Objective-C的撰写程式,因此在这一小节我们仅针对Objective-C的情况进行介绍,至于其他两种情况就留给有兴趣的读者再自行深入研究了。
x.4.3.1 Objective-C 物件
在拥有参考计数(reference-counted)的环境中,若我们在block中参考到Objective-C的物件,在一般的情况下它将会自动增加物件的参考计数,不过若以__block为修饰词的物件,参考计数则是不受影响。
如果我们在Objective-C的方法中使用block时,以下几个和记忆体管理的事是需要额外注意的:
l 若直接存取实体变数(instance variable),self的参考计数将被加1。
l 若透过变数存取实体变数的值,则只变数的参考计数将被加1。
以下程式码说明上面两种情况,在这个假设instanceVariable是实体变数:
1:dispatch_async (queue, ^{
2:// 因为直接存取实体变数instanceVariable ,所以self 的retain count 会加1
3:doSomethingWithObject (instanceVariable);
4:});
5:id localVaribale = instanceVariable;
6:dispatch_async (queue, ^{
7://localVariable 是存取值,所以这时只有localVariable 的retain count 加1
8://self 的 return count 并不会增加。
9:doSomethingWithObject (localVaribale);
10:});
网友评论