常見的變量有哪些?
在C語言中常見的變量如下:
- 自動變量(Auto),也可以稱為局部變量
- 函數參數(形參)
- 靜態變量(局部變量用static修飾)
- 靜態全局變量(全局變量用static修飾)
- 全局變量
而在OC中常用的,變量除了函數參數以外,其他都用到了
Block對這幾種變量的作用
第一篇文章(你真的知道Block是什么嗎?)中OC代碼打印結果如下:
Block 外 global_i = 2,static_global_j = 3,static_k = 4,val = 5
Block 中 global_i = 3,static_global_j = 4,static_k = 5,val = 4
Block外打印結果很正常,Block中會發現以下兩個問題:
- val 在block內部不能改變,報錯提示要加上__block,為什么?
- val這個自動變量的結果卻是不變的,為什么呢?
從第一篇文章(你真的知道Block是什么嗎?)的C++代碼分析可得:
- 全局變量global_i,靜態全局變量static_global_j,他們有與程序相同的生命周期,而且作用域很廣,因此在程序運行中隨時可以拿到,他們最終的結果并不意外
- 自動變量val 和靜態變量static_k
從__main_block_impl_0
這個結構體的構造函數中,我們可以看到,接收局部變量val的是int _val
,接收靜態變量的是int *_static_k
,然后在看__main_block_func_0
這個函數取出這兩個變量怎么取的,int *static_k = __cself->static_k; int val = __cself->val;
,從這里我們就能看出,自動變量val是值傳遞,而靜態變量static_k是地址傳遞(指針),這就解釋了,為什么Block中打印的自動變量沒變化的原因了. - 至于在block內部改變自動變量會報錯:必須加__block的原因
可以用作用域來解釋,從2.中我們知道,自動變量傳遞到block中的僅僅是自動變量的值而已,并沒有把自動變量傳進去,然而我們卻在block內部拿到自動變量對其操作,很顯然是拿不到這個變量的,所以必然錯誤,至于加__block的原理后面會講解.
Block中改變自動變量的兩種方式
- 傳遞內存地址指針到Block中。
- 改變存儲區方式(__block)。
先看第一種,從上面的結論我們看到,自動變量是值傳遞的,那么,我們可以設想一下,如果我們的局部變量不是基本數據類型,而是指針呢? 當外部的局部變量變化時,block中拿到的是變化后的,還是變化前的?此時在block中能修改局部變量嗎?還會報錯嗎?
測試代碼:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
int a = 1 ;
int *p = &a;
void (^myBlock)(void) = ^{
//這里可以修改了,并不會報錯__block了
*p = 3;
NSLog(@"Block中 a = %zd",*p);
};
a = 2;
NSLog(@"Block外 a = %zd",a);
myBlock();
return 0;
}
打印結果如下:
Block外 a = 2
Block中 a = 3
可以看到,如果自動變量是指針,那么在block中就可以改變該自動變量的值
結論
- 全局變量/靜態全局變量,可以在block內外任意改變
- 靜態變量是指針傳遞,因此也可以在block內外任意改變
- 自動變量是值傳遞,因此不能在block內部改變其值,而且block中拿到的是當時block捕獲的那個值,并不是最新值
- 自動變量若想和靜態變量一樣,那么這個變量可以是指針類型(非基本數據類型),就可以達到與靜態變量效果一樣了