2013-02-18 87 views
8

我使用的是Xcode 4.6,我有一個頭文件,其中包含了我在代碼中使用的一些常量。我不想使用預處理器指令,因爲我希望它們能夠正確鍵入等。如何使用帶有「未使用變量」警告的類型常量?

例如,我有這樣的代碼在我的.h文件之一:

static NSString *kErrorCannotDivideByZero = @"Error: Cannot divide by zero"; 

我用它在相應.m文件:

[self showToast:kErrorCannotDivideByZero]; 

我得到警告:

/path/to/my/headerFile.h:32:18: Unused variable 'kErrorCannotDivideByZero' 

我知道這只是一個警告,但我已經有大約50個這些警告堵塞了我的編譯器輸出。

爲什麼我得到這個警告,我該如何正確解決它?

我對簡單地抑制所有未使用的變量警告並不感興趣,因爲我確實希望得到合法的警告。

+1

你確定標題中有靜NSString的文件,而不是在.m文件(並具有隻是一個外部的靜態的NSString在標題中)是不是你的問題的原因?我懷疑生成了一個不同的靜態實例,每次將它包含到.m文件中。 – 2013-02-19 00:16:43

+0

我想要一些可重複使用的字符串,我可以在整個應用程序中使用。你會建議什麼? – 2013-02-19 00:19:03

+0

正如Josh所說,「extern NSString * foo;」然後在.m中聲明真正的非靜態實例ONCE。或者只是#define FOO @「StringLiteral」 – 2013-02-19 00:19:56

回答

15

作出聲明。你正在做的是爲包含你的頭文件的每個翻譯單元創建一個變量,這就是爲什麼Clang會警告你,因爲它是一個合法的未定義的變量。 extern關鍵字告訴編譯器,變量的定義可以在別的地方找到(它可能在同一個翻譯單元中,或者可能在另一個翻譯單元中)。

在你的頭,具有:

// declare that the constant exists somewhere 
extern NSString * const kErrorCannotDivideByZero; 

而在一個.m文件(通常是共享相同的名稱作爲標題中的一個),放

// define the constant, i.e. this is where it exists 
NSString * const kErrorCannotDivideByZero = @"Error: Cannot divide by zero"; 

變量聲明extern允許編譯器確保您正確處理變量,即使它不知道它在哪裏定義(例如,您不能將它用作NSArray)。鏈接器的工作是確保你確實在某個地方定義了它。

+0

如果Foo.h具有extern,並且Foo.m定義了它指向的內容... bar.m #import Foo.h並且能夠使用kErrorCannotDivideByZero? – 2013-02-19 01:16:02

+0

@ KennyWyland:是的,絕對。頭文件中的聲明只告訴編譯器,某個地方存在名爲'kErrorCannotDivideByZero'的'NSString *'類型的對象。鏈接器(將所有編譯後的源文件鏈接在一起)將解析對* one *定義的所有引用。 – dreamlax 2013-02-19 01:34:16

+0

只是爲了擴展這個解決方案:我通常做的是在MyIncludes.h中聲明我的外部變量。不需要是const; 'extern NSString * EnglishHiddenKey;'會做得很好。現在我將MyIncludes.h導入到.pch文件中,以便每個人都可以在全局中看到它,並且我在MyIncludes.m中定義了我的extern,例如'NSString * EnglishHiddenKey = @「englishHidden」;' – matt 2013-02-19 02:06:22

12

Clang將允許您將警告標誌推入並從「診斷」堆棧中彈出:"Controlling diagnostics via pragmas"。你可以像這樣包裝某些代碼片段:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wunused-variable" 

static NSString *kErrorCannotDivideByZero = @"Error: Cannot divide by zero"; 

#pragma clang diagnostic pop 

告訴Clang你知道這些不被使用,在這個特殊情況下沒關係。

順便說一句,你可能不希望定義這些在多數民衆贊成被導入到許多不同的地方文件的變量 - 這是造成約可變重定義鏈接錯誤的好辦法(儘管如果變量是全球這隻會發生鏈接 - 申報/定義static)。像這樣的常量的通常模式是將extern聲明置於頭部中,並且將另一個文件中的變量定義爲。詳情請參閱Referencing a static NSString * const from another class

由於dreamlax已經指出,你實際上得到這些警告,因爲每個導入你的頭文件都獲得自己的副本static變量;當我提出上述#pragma技術時,我誤解了你所要求的。

+0

+1爲您答案的第二部分;這是正確的解決方案。 – 2013-02-18 23:49:52

+0

不會有任何變量重定義錯誤,因爲變量聲明爲「靜態」,所以它沒有外部鏈接。 – dreamlax 2013-02-18 23:54:45

+0

哦,對,每個導入標題的文件都有自己的變量@dreamlax? – 2013-02-19 00:24:56

4

讓您的常量const:在你的頭extern寧可static

static NSString * const kErrorCannotDivideByZero = @"Error: Cannot divide by zero"; 

(和其他人指出的那樣,使用extern和實現文件中定義)

+0

+1:蘋果不僅在他們的頭文件中使用了'const',而且也意味着你不能意外地重新分配'kErrorCannotDivideByZero'。 – dreamlax 2013-02-19 00:04:56

+0

我最初在代碼中使用了'const',但是在將NSStrings傳遞給各種apis時,我收到了許多關於不匹配類型的警告。 – 2013-02-19 01:21:29

+4

當你聲明爲const NSString *(const指針)而不是'NSString * const'(常量指針)時,通常會發生這種情況 – Sebastian 2013-02-19 01:31:34

2

也許,不是將它們初始化爲字符串文字,而是運行一個初始化函數,該函數從特定於語言環境的文件加載這些值,以使錯誤處於已翻譯的語言中。當你的初始化函數賦值給該變量時,你的編譯器可能會試圖相信該變量需要存在才能使編譯成功。

+0

提供一個'Localizable.strings'文件來翻譯錯誤會更容易。 – dreamlax 2013-02-18 23:53:57

+0

假設OP不希望他/她可以在他/她的C項目中使用的答案也是愚蠢的,因爲他/她也標記了「C」。 – Sebivor 2013-02-18 23:56:49

+0

我不認爲它是愚蠢的。 Objective-C是C的一個超集,雖然提供的代碼明顯是Objective-C,但他得到的警告是由於Objective-C的根源在C中。而且,即使對於C項目,也存在用於本地化的解決方案。 GNU'gettext'。 – dreamlax 2013-02-19 00:03:23

0

您可以將所有靜態變量聲明移動到相應的.m文件中。這應該帶走所有這些「未使用的變量」警告。原因是靜態變量僅限於文件級範圍。

1

海灣合作委員會(我認爲鐺)不警告有關未使用的常量。要注意的一個陷阱是指針需要是const指針,而不僅僅是指向const的指針;因此,正確地宣佈,將不會觸發任何警報未使用的字符串常量,你需要:

const char * const myConst = "myConst"; 
相關問題