[譯] 4 種預(yù)編譯頭文件(PCH)削弱代碼的方式

如果使用得當(dāng),預(yù)編譯頭文件可以為您節(jié)省寶貴的編譯時間。但如果使用不當(dāng),預(yù)編譯頭文件可能會隱藏源代碼中的問題,而這些問題可能會在你嘗試在另一個項目中重復(fù)使用部分源代碼時才被發(fā)現(xiàn)。

本文是Objective-C 中的代碼氣味系列文章中的一篇。

預(yù)編譯頭文件的用途

發(fā)明預(yù)編譯頭文件的目的只有一個:"加快編譯速度"。與反復(fù)解析相同的頭文件相比,這些文件只需提前解析一次。速度非常重要!編譯速度越快,就能越快查看最近的更改是否成功,越快完成反饋循環(huán)。

在 Xcode 中,您可以將所需的頭文件包含在 "prefix header"中,并啟用 "Precompile Prefix Header",從而對其進(jìn)行預(yù)編譯。但前綴頭文件背后的理念與預(yù)編譯不同。前綴頭文件隱含在每個源文件的開頭。例如,如果你的前綴頭是 Prefix.pch,那么每個源文件就會偷偷地

#import "Prefix.pch"

將其放在文件頂端,比其他任何東西都先。這對于整個項目的 #defines 來說很方便。(請記住,一般來說,#defines 是一種代碼氣味)。

對于預(yù)編譯頭文件來說也很方便。事實上,每個源文件都包含這些預(yù)編譯的頭文件,這也是前綴頭文件的一個特點。

這就是事情開始出錯的地方......

預(yù)編譯頭文件的存在并不是為了讓你省去打字的麻煩

Apple 的 iOS 項目模板以 Prefix.pch 開始,其中包括 FoundationUIKit。從編譯速度的角度來看,這非常合理。問題是,人們注意到了這一點,并說:"這些文件已經(jīng)隱含包含了。所以我不需要再次包含它們"。發(fā)現(xiàn)這種副作用后,一些程序員開始向 Prefix.pch 添加更多的頭文件。因為這樣就不用再 #import(導(dǎo)入)了。

目的從 "盡可能快地編譯這個項目 "轉(zhuǎn)變?yōu)?"節(jié)省自己的打字時間"。Stack Overflow 的一個問題就反映了這一點,它問道:"為什么有重復(fù)的#import?甚至維基百科的前綴詞條也反映了這一不正確的結(jié)論:"因此,沒有必要明確包含上述任何文件"。這種誤解非常普遍。

這完全是錯誤的。

過度依賴預(yù)編譯頭文件的四個問題

問題在于,要成功編譯一個文件,僅有成對的頭文件(.h)和實現(xiàn)文件(.m)已經(jīng)不夠了。你還需要 Prefix.pch——不是因為它們是預(yù)編譯的,而是因為它們是隱式包含的。

"所以呢?"你問。"是什么阻礙了你?"基本上,你最終會創(chuàng)建不完整的源文件。至少有四種方式會導(dǎo)致問題:

1、源文件無法復(fù)制到不同的項目中

假如你在前綴頭文件中添加了 <QuartzCore/QuartzCore.h>。某個源文件使用了 QuartzCore。試著將該源文件復(fù)制到另一個項目中。

很有可能無法編譯,因為另一個項目的預(yù)編譯頭文件不同。你設(shè)法創(chuàng)建了一個不可移植的源文件!

2、依賴關(guān)系被隱藏

任何導(dǎo)入其他文件的系統(tǒng)都有一個好處,那就是可以顯示文件的依賴關(guān)系。你可以掃描 .h 或 .m 文件的開頭,看看它還使用了哪些其他文件。這可以讓你快速了解文件的范圍。

如果你的導(dǎo)入是隱式綁定在前綴頭文件中,情況就不一樣了。

3、依賴關(guān)系被掩藏

一個大型項目可能有大量的預(yù)編譯頭文件。假設(shè)你正在查看一個源文件,并試圖找到它的依賴關(guān)系。你很聰明地意識到,早期的程序員依賴預(yù)編譯頭文件來節(jié)省輸入,省略了許多 #import。所以你也查看了前綴文件。

但是,如果 Prefix.pch 中的 #import 語句不只幾條,你的源文件需要哪些語句?全部?不需要?一些?哪些?

4、依賴關(guān)系失控

即使將所有 #imports明確化,也很容易產(chǎn)生爆炸性的文件依賴關(guān)系。讓依賴樹保持穩(wěn)定已經(jīng)很不容易了。

但是,如果沒有努力做到:
a)使所有 #import 明確化;
b)馴服它們,
這些依賴關(guān)系就會悄無聲息地發(fā)展到不可收拾的地步。依賴關(guān)系的腐爛會在不知不覺中蔓延多年,直到為時已晚。突然間,你要開發(fā)一個新項目,卻沒有一種簡潔的方法來重用以前的代碼,而又不會把它們都變成大量浪費的垃圾。

查找并修復(fù)缺失的 #import

由于 Xcode 將前綴頭文件與預(yù)編譯頭文件結(jié)合在一起的方式,省略 #import 語句是一種常見的 Objective-C 代碼氣味。但這是一種不尋常的現(xiàn)象,因為這種氣味本身可能在很長時間內(nèi)都不會被注意到。(無聲卻致命?。?。

要解決問題,就必須找到問題所在。而要想找到問題,就必須暫時移除阻嗅器:

  1. 編輯你的前綴文件。暫時注釋掉所有 #import#include 語句。(譯者注,PS: 個人感覺對于一些明確的基類或者基礎(chǔ)的三方庫就別注釋了??)
    2、嘗試構(gòu)建您的項目。你會立刻發(fā)現(xiàn)問題所在。

項目越大,做第一遍修復(fù)工作所需的時間就越長。如果您覺得累了,可以把它放在一邊,稍后再繼續(xù)清理。但我還是希望你能把項目清理干凈。明確依賴關(guān)系是減少依賴關(guān)系的重要第一步。

譯自 Jon Reid 的 4 Ways Precompiled Headers Cripple Your Code
侵刪

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容