OC中的全局變量,靜態全局變量,常量,靜態局部變量

作者:Love@YR
鏈接:http://blog.csdn.net/jingqiu880905/article/details/51997126
請尊重原創,謝謝!

首先說幾個詞:
頭文件指.h文件,源文件指.m文件。

extern可置於變量或者函數前,以表示變量或者函數的定義在別的文件中,提示編譯器遇到此變量或函數時,在其它模塊中尋找其定義。另外,extern也可用來進行鏈接指定

用extern int a是聲明,而直接int a或者int a =10 或者extern int a = 10是指定義。聲明可以多次,定義只能一次。多次定義的那就不是同一個變量了。

全局變量是指定義在@implement(@interface)和@end之外的變量。全局變量即外部變量。

下面我們假設有4個文件,A.h A.m 和B.h B.m

  1. 在A.m裏定義一個全局變量int i =1, 在B.m裏直接訪問。
    A中的任意方法都能訪問i,但B中方法訪問i時
    預編譯不能通過,報use of undeclared identifier _i錯誤

  2. 在A.m裏定義一個全局變量int i =1, 在B.m裏 extern int i。
    A中的任意方法都能訪問i,B中的方法對i也是可讀可寫。他們用的是同一個i

  3. 在A.m裏定義一個靜態全局變量static int i =1,在B.m裏直接訪問。
    A中的任意方法都能訪問i,但B中方法訪問i時
    預編譯不能通過,報use of undeclared identifier _i錯誤

  4. 在A.m裏定義一個靜態全局變量static int i =1,在B.m裏 extern int i;
    A中的任意方法都能訪問i,但B中方法訪問i時
    編譯不能通過,報Undefined symbols i 錯誤

  5. 在A.m和B.m裏分別定義靜態全局變量static int i=200; static int i =300;
    則互不影響,有兩個同名但不同存儲位置的i,各源文件裏的方法訪問各自源文件裏的i。

  6. 在A.m和B.m裏分別定義靜態全局變量static int i=200; 和全局變量 int i =300;
    仍然互不影響。如果我在A裏extern int i了,A中方法訪問的i仍然是200那個,而不是B中那個i

  7. 在A.m和B.m裏分別定義全局變量int i=200; 和 int i =300;
    則編譯不通過,報duplicate symbol _i錯誤
    同樣在A.m和B.m裏分別定義全局常量const int i =200;和全局變量int i =300 也編譯不通過
    同樣的上面7條都適用於全局常量。
    const int i = 11;和 static const int i =1
    不同的只是不加const可寫,加了const只可讀。

  8. 在A.h裏聲明全局變量extern int i;
    在A.m裏定義全局變量int i = 1;
    在其他源文件裏import "A.h"即可訪問A中定義的i

結論:
非靜態全局變量具有全局作用域。
其只需在一個源文件中定義,就可以作用於所有的源文件。
其他不包括全局變量定義的源文件可以通過extern的方式引用。 (對應第1,2條)

靜態全局變量的作用域只在其源文件內,不能被其他源文件使用或修改,所以不必擔心其它源文件使用相同變量名,彼此相互獨立。 ( 對應第3,4,5條)

如果全局變量和局部變量重名,則在局部變量作用域內,全局變量會被屏蔽不起作用。(對應第6條)

全局變量不能被重複定義,可以多次聲明( 對應第7條)

我們一般不要在.h文件裏定義全局變量,這樣一旦.h被import,相當於.h的代碼拷過去一份,會出現多次定義的情況。
如果是非static的直接編譯報錯duplicate symbol 。
如果是static的,多少個源文件import就會生成多少個作用於此源文件的靜態全局變量。(效果和第5條一樣)

下面說下靜態局部變量:
(非靜態)全局變量的作用域是整個源程序,靜態全局變量的作用域是定義它的那個源文件,靜態局部變量的作用域是定義它的那個方法。

以上三者都是在靜態數據存儲區分配,只在程序開始運行時初始化一次(並不是該類實例化後才初始化的),程序運行期間一直都在,自動賦值爲缺省值。
都是在編譯時就初始化了。
在下一次使用時還能保存原來的賦值

所以說上面三者是存儲位置和生命週期都一樣,作用域不同。static關鍵字告知編譯器自己僅在變量的作用域範圍內可見。

所以說如果一個方法裏有句static int i = 9; 並不是每次走到這個方法的時候這個i就賦值成9了,只是初始化的時候是9而已,實際上編譯之後相當於這句話被從此方法裏拿出來了。

而非靜態的局部變量存儲在棧上,出了方法就釋放了。下次使用就新初始化一下

最後說一下關於定義在@implement 和@end之外的C函數:
C函數不依賴於類和對象。
作用域爲定義它的源文件。其他文件需要調用import就可以了。
參考:http://bbs.itheima.com/thread-138029-1-1.html

再最後說下關於OC裏的類方法:


  self.arr =[@[@"str1", @"str2"]mutableCopy];
    [FirstViewController anyClassMehodWithParam:self.arr];
    
    
+(void)anyClassMehodWithParam:(NSMutableArray *)arr
{
    variableStr =@"";//實例變量variableStr,報錯
    [self.arr replaceObjectAtIndex:0 withObject:@"modifiedStr1"];//arr屬性,報錯
    
    NSLog(@"arr is %@",arr);
    [arr replaceObjectAtIndex:0 withObject:@"modifiedStr1"];
    
    [self anyClassMethod];//類方法
   
    [self deallocReloadable];//實例方法,報錯
    FirstViewController *fv = [[self alloc]init];
    [fv deallocReloadable];
    
	timeDuration=22;//全局變量timeDuration
	i = 33;//靜態全局變量i
	static int i =6;
    NSLog(@"i = %d",i);//靜態局部變量i

}

上面例子說明:
類方法裏不能訪問實例變量instance variable
類方法裏不能訪問屬性
類方法裏不能直接調用實例方法

類方法可以直接調用類方法(用self)
類方法可以直接訪問全局和靜態變量
類方法可以通過創建對象來訪問實例方法

1.棧 - 由編譯器自動分配釋放
2.堆 - 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收
3.全局區(靜態區),全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。- 程序結束釋放
4.另外還有一個專門放常量的地方。- 程序結束釋放

全局方法或變量是在一個.m文件的@implement之前或者在@end之後定義的方法或者變量
或者 在一個.h文件的@interface之前或者在@end之後聲明的方法或者變量
方法前無+/-, 因爲和類無關了,不能用self調用,也不能用類名調用
如void add() 直接調用就add();

2018年10月25日補充:
在a.h裏static CGFloat cellHeight = 30;
然後某個b.m裏引用此a.h
會生成一個不同的cellHeight (相當於多次定義 那麼就不是同一個變量)
在b.m裏把cellHeight重新賦值爲60,會發現a.m中的值不會改變!
所以 不要把static 變量放.h裏定義然後在.m裏引用.h!

發佈了56 篇原創文章 · 獲贊 28 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章