2014-12-11 76 views
4

在我的iOS/Objective C項目中,我經常有一個constants.h文件和我的API密鑰等。直到今天,我已經宣佈我的常量,staticconst像這樣:static const與extern const不同嗎?

static NSString * const kAPIKey = @"wembvkejrvb43789gvbiu2bvfake"; 

這工作得很好,但不幸的缺點,我可以只創造原語和文字NSString的常量,本質上。其他對象,如UIColor對象,不能存儲在這個常量中,因爲它們不能用靜態文字語法(我的理解,需要引用)初始化。

閱讀一些C++的文檔後,我明白了一些東西:

  • static是不必要的,因爲const隱含靜態的。
  • 調用NSString * const x實際上是在x中聲明一個常量和不可變的值。我無法改變價值,但可能能夠改變x點。
  • 此常量有內部鏈接,意味着該值立即定義(可在編譯時推斷)。

這些結論是否正確?

extern constextern const有什麼區別?我假設他們是外部鏈接的(因此extern關鍵字)。它們是在運行時定義的嗎?我可以創建某種動態extern const可以使用類方法返回的值設置嗎?

例如,我想創建一個全局範圍的常量,其中包含一個UIColor值。我想用[UIColor colorWithRed:green:blue:alpha:]類的方法構造這個顏色值。這顯然不適用於我一直使用的內部鏈接常量(我假設是因爲它發生在編譯時) - 但它可能使用外部常量,可能在+initialize方法中設置?

任何關於此行爲細節的闡述都將非常有幫助。

回答

8

靜態是不必要的,因爲const是隱式靜態的。

不,這是不正確的。

static在文件範圍(即在任何方法或函數之外)使用時,表示該變量僅在該文件中可見。

extern表示該變量是在其他文件中定義的。

const表示變量不能被修改。

考慮字符串。通常情況下,你將有一個實現文件(名.M結束),它定義了一些常量字符串指針:

NSString *const SomeString = @"some string"; 

你可能想使用從其他文件相同的不變。如果是這樣,你可以聲明添加到該解釋對這個變量在其他地方定義編譯頭(名.H結尾)文件:

extern NSString *const SomeString; 

這將讓你在任何文件中導入使用SomeString頭文件。另一方面,你可能會決定你確實要做而不是想要在執行文件外面使用常量。在這種情況下,你可以聲明它static(在實現文件再次):

static NSString *const SomeString = @"some string"; 

,並會阻止其使用從文件之外。

調用NSString * const x實際上宣告以x恆定的和不可改變的值。我無法改變價值,但可能能夠改變x點。

對,它聲明指針x是不變的 - 你不能改變它。如果實際NSString因爲實例NSString不可變,您也無法更改它指向的值。

這個const有內部聯繫,意思是這個值是馬上定義的(在編譯時可以推測)。

我會拿第五個 - 我不確定編譯器如何處理常量字符串。儘管如此,我認爲使用它作爲心理模型是安全的;無論如何,在您的代碼使用它之前,該字符串將被定義。

+0

如果'static'限制範圍,並且'extern'表示該變量是在其他地方定義的,那麼我甚至不需要extern'作爲全局常量?我可以在頭文件中使用NSString * const SomeString = @「Some String」,並從任何導入該頭文件的文件中訪問SomeString?換句話說,全局常量是否需要'extern'? – cdstamper 2014-12-11 00:51:49

+0

如果你這樣做(在頭文件中定義'SomeString'),如果頭文件包含在多個實現文件中,你會得到關於多個定義的錯誤。 'extern'給你一種聲明存在其他地方定義的變量的方法,這樣聲明就可以被導入到許多文件中,但'SomeString'只被定義*一次。 – Caleb 2014-12-11 00:56:12

+0

非常有趣。所以我的'static const'模式只工作,因爲我已經在一個空的頭文件中聲明瞭它們在任何類之外,然後我將它們包含在其他地方。必須在編譯時使用接受的文字來定義'extern'常量,或者有什麼方法可以創建一個'動態'常量(可能在+初始化中定義)。 – cdstamper 2014-12-11 01:11:11

1

關於你的具體編程問題,如何創建一個編譯時定義的顏色對象:你不能,因爲除了少數語言提供文字語法外,對象是在運行時創建的。

,但你仍然可以做它優雅在運行時,沒有任何除了全球範圍內,以同樣的方式在SDK中......

@interface UIColor (RainbowAddition) 

+ (UIColor *)chartruseColor; 

@end 

@implementation UIColor (RainbowAddition) 

+ (UIColor *)chartruseColor { 
    // bonus: this is really chartruse... according to the internet 
    return [self colorWithRed:0.5 green:1.0 blue:0.0 alpha:1.0]; 
} 

@end 

http://cloford.com/resources/colours/500col.htm

+0

我當然明白我的問題的邏輯解決方案,謝謝你的回答。我只是想了解其中的根本原因。我知道文字(除了容器文字)似乎是在編譯時創建的;我只是不明白*爲什麼*。 – cdstamper 2014-12-11 01:01:04

+0

@cdstamper - 它不是在編譯時創建的文字,而是可以由文字描述的對象。只有那些可以在編譯時創建的原因是,只有那些可以被編譯器描述爲一系列輸入標記(由語言定義提供,在3.6版中包含數字和數組以及字典時有了很大的改進)。 – danh 2014-12-11 02:00:08

1

的Objective-C是一個純粹的延伸C,C++不是。

在全球範圍:

    在C(和Objective-C)
  • 寫入const相當於extern const(外部連接);
  • C++寫作const相當於static const(內部鏈接)。

無論是在C(和Objective-C)和C++,建立一個全球範圍的const可以定義它,只是一個時間,在一個源文件等extern const TYPE identifier = VALUE;並聲明它(通常在頭文件)如:extern const TYPE identifier;(閱讀它:我在全局鏈接級別的其他地方定義了此常量)。