2009-12-15 34 views
7

我不知道爲什麼,但有時我已經成功地解決一些由.h文件移動到#import "someClass.h" .m文件編譯錯誤,最顯着的可可:導入頭文件和導入主文件有什麼區別?

error expected specifier-qualifier-list before 'someClass' 

。這也與我遇到的一些其他問題一起工作,這些問題與標題相關(從我的觀點來看是神祕的)。

一些粗略的谷歌搜索出現了答案:「從不在頭文件中導入頭文件」,這就是通知停止的地方。

要麼我已經完全做到了這一點,或者我已經從某個地方拿起了這個習慣,但是我認爲這個頭文件是頭文件被導入的地方。顯然不是,但任何人都可以向我解釋爲什麼是這樣的,導入頭文件的首選方式是什麼?

回答

10

除非您從包含的類繼承,否則不應在標題中包含標題。如果您需要包含一個對象作爲接口變量,則應該使用@class指令代替;這會告訴編譯器該標識符引用了一個類。

相反,只在實現文件中導入標題。編譯器會知道你的實例變量是指向對象的指針,但是在解析頭文件時它不知道對象的細節。它需要知道的是它是一個班級。編譯器可以在解析實現文件時看到該類的方法;此時,它確實需要該類,以驗證它是否響應了您要發送的消息。


更新:我會更新我的回答一些問題後迴應,但Rob Napier has a good follow-up

+1

'typedef's和'protocols'怎麼樣? – Joost

+0

你不會碰巧知道一個教程,或者使用它的代碼示例? – gargantuan

13

約翰給出了很好的建議,但這裏有更多的背景,關於whys,因爲和例外。

避免將標題導入標題有兩個目的:改進增量構建時間和避免循環依賴。如果導入A.hB.h並導入B.hC.h,然後每次在A.h改變任何東西的時候,你必須重新編譯C.m,即使C.m是沒有使用任何的A.h定義的東西。這可能會導致非常可怕和不必要的構建流失,特別是如果您的頭文件經常更改(如在開發的早期階段常見)。

第一個目標值得稱讚,但對於小型項目,誰在乎?你有一個四核Pro,一個完整的構建需要幾分鐘,對吧?但是你仍然需要擔心第二個問題:循環依賴。 A.h參考類別BB.h參考類別A。這實際上可能經常發生,並且可能非常無辜地進入系統。集合對象可能會引用其包含的對象的類型,並且對象可能會引用集合對象的類型。它只需要一個引用,因爲某些方法需要或返回該類型。如果您有標題導入其他標題,則發生這種情況的可能性會迅速接近統一。你用遞歸導入結束了,編譯時錯誤可能令人興奮。 「我知道,typdef被定義了!它就在那裏!它是進口的!「但是,當你導入這個頭文件時,它還沒有被解析,這是什麼導致你的錯誤如上所述

因爲這個原因,即使你不關心構建時間你應該),避免導入標題變爲頭......除了....

有些頭你進口。你當然父。文件定義@protocol你實現或typedef使用。所以,是的,你必須包括這些。

那麼系統頭怎麼樣?那麼,他們永遠不會去c因爲他們不會引起遞歸進口,所以他們沒事。我不鼓勵人們在系統頭文件中使用@class轉發聲明。它爲您的標題的用戶創造了額外的工作,沒有任何價值。要獲得良好的標題衛生,請記住將系統標題放在<尖括號>中,並將標題放在「引號」中。

所以這不是一個小問題,但簡單的規則是:避免在編譯器允許的任何時候將用戶頭文件導入到其他用戶頭文件中。

+0

非常感謝你。 – gargantuan

0

您不僅將頭文件包含在實現文件中,還包含到使用該類的其他文件中。如果你在頭文件中包含了所有的依賴項,那麼包含該頭文件的所有其他文件僅僅用於使用它定義的特定類,它們本身也會包含所有依賴項。

這不僅嘈雜,但當你有類引用自己的時候會導致問題。每個類都必須在另一個類之前導入,這導致先導入一個類,然後再找不到另一個類的類型。這會導致您發佈的模糊錯誤消息,這基本上意味着編譯器無法找到someClass類型。

通過將您的導入移動到您的實現文件中,並在頭文件中正向聲明類和類型(使用@class@protocol等),可以避免這些問題。

相關問題