04 編碼規(guī)范:如何使用 SwiftLint 統(tǒng)一編碼規(guī)范?

在軟件開發(fā)領(lǐng)域有很多有趣且重要的話題,比如使用什么樣的系統(tǒng)架構(gòu)來讓代碼更容易維護(hù),使用哪些第三方庫能提高開發(fā)效率,等等。但也有一些話題不僅無趣,還很難得出結(jié)論,比如像下面這行變量定義,里面的空格哪個正確?

let name: String = "Jake"
let name : String = "Jake"
let name :String = "Jake"
let name: String= "Jake"
let name: String="Jake"

還有代碼縮減,到底是用 2 個空格還是 4 個?這就像豆?jié){到底是喝甜的還是喝咸的一樣,并沒有標(biāo)準(zhǔn)答案。也因此,出現(xiàn)了許多永無休止的討論。特別是當(dāng)新成員所提交的代碼風(fēng)格,與團(tuán)隊其他成員有很大的區(qū)別時,往往會出現(xiàn)溝通與協(xié)作問題,甚至發(fā)生爭執(zhí)而影響工作。此時,團(tuán)隊如果有一套統(tǒng)一的編碼規(guī)范,那么這樣的問題就很容易解決。

除了能促進(jìn)溝通協(xié)作,一套統(tǒng)一的編碼規(guī)范還能降低代碼維護(hù)的成本和減少 Bug 的數(shù)量。此外,由于規(guī)范往往由團(tuán)隊資深開發(fā)者指定并不斷完善,也有助于其他團(tuán)隊成員快速成長。

既然統(tǒng)一的編碼規(guī)范由那么多優(yōu)點,那么我們?nèi)绾卧趫F(tuán)隊中實施統(tǒng)一編碼規(guī)范呢?在 iOS 開發(fā)領(lǐng)域,使用 SwiftLint 能有效地建立和改進(jìn) Swift 項目的編碼規(guī)范。接下來我就和你聊聊這方面的內(nèi)容。

安裝 SwiftLint

安裝 SwiftLint 的方式有很多種,例如使用 Homebrew,Mint,下載 SwiftLint.pkg 安裝包等等。但我只推薦 CocoaPods 這一種方法,因為通過 CocoaPods 可以有效地管理 SwiftLint 的版本,從而保證團(tuán)隊內(nèi)各個成員都能使用一模一樣的 SwiftLint 及其編碼規(guī)范。

通過 CocoaPods 來安裝 SwiftLint 非常簡單。在 Moments App 項目中,我們在Podfile文件中添加SwiftLintPod 即可。

pod 'SwiftLint', '= 0.41.0', configurations: ['Debug']

由于我們只在開發(fā)環(huán)境下使用 SwiftLint,因此配置了只有Debug的 Build Configuration 才生效。

為了每次編譯完都使用 SwiftLint 來檢查代碼,我們需要在主 App TargetMoments的 Build Phases 里面添加Run SwiftLint步驟。然后配置它執(zhí)行"${PODS_ROOT}/SwiftLint/swiftlint"命令。

[圖片上傳失敗...(image-3f40a4-1684745180821)]

這里要注意,由于 SwiftLint 的設(shè)計是檢查有效的 Swift 代碼(編譯通過的代碼就是有效的代碼),我們需要把Run SwiftLint步驟放在Compile Source步驟之后。否則 SwiftLint 可能會反饋一些錯誤的結(jié)果。

有了上面的配置以后,每次編譯程序, SwiftLint 都會自動執(zhí)行檢查,我們可以在 Xcode 上修正這些警告信息來保證編碼規(guī)范的統(tǒng)一。

[圖片上傳失敗...(image-a83d52-1684745180821)]

例如上面的截圖所示,SwiftLint 告訴我們空格的使用不正確。

那么,這些警告信息到底怎樣來的呢?我們一起看看.swiftlint.yml文件吧。

.swiftlint.yml 文件

當(dāng)我們執(zhí)行 SwiftLint 命令時,它會自動幫我們啟動一堆編碼規(guī)則,并掃描和檢查我們的項目。這些規(guī)則有comma(逗號前后的空格處理),private_over_fileprivate(優(yōu)先使用 priviate),force_cast(避免強(qiáng)制轉(zhuǎn)型)等等 。詳細(xì)規(guī)則列表你也可以在SwiftLint 官網(wǎng)找到。

但正如 SwiftLint 的作者所說: “規(guī)則存在,但并不意味著你必須用它”。我們需要根據(jù)團(tuán)隊自身的情況和成員的統(tǒng)一意見,來決定需要啟動和關(guān)閉哪些規(guī)則。此時,就需要用到 .swiftlint.yml 文件了。

.swiftlint.yml主要用于啟動和關(guān)閉 SwiftLint 所提供的規(guī)則,以及自定義配置與規(guī)則。一旦我們有了 .swiftlint.yml 文件以后,SwiftLint 在執(zhí)行過程中會嚴(yán)格按照該文件的定義來掃描和檢查代碼。由于 .swiftlint.yml 是一個純文本文件,我們可以通過 Git 統(tǒng)一管理,這樣能保證整個團(tuán)隊在執(zhí)行 SwiftLint 的時候都會得到一模一樣的效果,從而保證了整個團(tuán)隊代碼規(guī)范的一致性。

規(guī)則設(shè)置

SwiftLint 提供了disabled_rules,opt_in_rulesonly_rules三種規(guī)則設(shè)置方法。其中,disabled_rules能幫我們關(guān)閉默認(rèn)生效的規(guī)則,而opt_in_rules可以啟動默認(rèn)關(guān)閉的規(guī)則。

另外,SwiftLint 所提供的每條規(guī)則都有一個叫作Enabled by default的屬性來表示該規(guī)則是否默認(rèn)啟動。例如class_delegate_protocol規(guī)則是默認(rèn)啟動的,而array_init規(guī)則是默認(rèn)關(guān)閉的。

disabled_rules:
  - class_delegate_protocol
opt_in_rules:
  - array_init

上面的配置表示,關(guān)閉默認(rèn)生效的class_delegate_protocol,并同時啟動array_init。

雖然使用disabled_rulesopt_in_rules能夠完成配置,但我不推薦你使用它們 ,而是用only_rules來定義每條生效的規(guī)則。

我們在 Moments App 項目中也使用了only_rules。你可以在拉勾教育的代碼倉庫找到該 .swiftlint.yml 文件來查看項目啟動的所有規(guī)則。由于only_rules是 SwiftLint 0.41.0 引入的,如果你需要以前版本,可以使用whitelist_rules來替代。下面是 .swiftlint.yml 文件中的部分規(guī)則。

only_rules:
  - array_init
  - attributes
  - block_based_kvo
  - class_delegate_protocol
  - closing_brace

通過only_rules,我們可以把每一條規(guī)則明確添加到 SwiftLint 里面。這樣能保證我們整個團(tuán)隊都使用一致的規(guī)則,而不會像使用disabled_rulesopt_in_rules那樣,隨著 SwiftLint 默認(rèn)規(guī)則的改變,導(dǎo)致最終啟動的規(guī)則不一樣。

自定義配置

在我們配置一條規(guī)則的時候,為了符合團(tuán)隊自身的情況,可以修改其默認(rèn)配置。例如line_length的默認(rèn)配置是當(dāng)一行代碼多于 120 個字符的時候會報告編譯警告,而多于 200 個字符的時候報告編譯錯誤。

[圖片上傳失敗...(image-f92bb5-1684745180821)]

來源:SwiftLintFramework Docs

我們可以在 .swiftlint.yml 文件中修改這些配置。

line_length: 110
file_length:
  warning: 500
  error: 1200

上述的配置表示我們修改了line_length的配置,當(dāng)一行代碼多于 110 個字符(而不是默認(rèn)的 120 個字符)時就會報告編譯警告。我們也可以同時覆蓋編譯警告和編譯錯誤的配置,例如把file_length的編譯警告改成 500,而編譯錯誤改成 1200。

自定義規(guī)則

除了 SwiftLint 所提供的默認(rèn)規(guī)則以外,我們還可以自定義規(guī)則。例如在 Moments App 項目中,我就自定義了“不能硬編碼字符串”的規(guī)則,具體如下:

custom_rules:
  no_hardcoded_strings:
    regex: "([A-Za-z]+)"
    match_kinds: string
    message: "Please do not hardcode strings and add them to the appropriate `Localizable.strings` file; a build script compiles all strings into strongly typed resources available through `Generated/Strings.swift`, e.g. `L10n.accessCamera"
    severity: warning

該規(guī)則no_hardcoded_strings會通過正則表達(dá)式來檢查字符串是否進(jìn)行了硬編碼。如果是SwiftLint 會根據(jù)我們的自定義規(guī)則顯示警告信息,如下圖所示。

[圖片上傳失敗...(image-d7244e-1684745180821)]

排除掃描文件

默認(rèn)情況下 SwiftLint 會掃描和檢查整個項目的所有代碼。因為一些第三方依賴庫的源碼風(fēng)格可能和我們團(tuán)隊的風(fēng)格不一致,為了方便使用第三方依賴庫,我們可以用excluded來把它排除在外,避免掃描和檢查。示例如下:

excluded:
  - Pods

現(xiàn)在我們已經(jīng)通過配置 .swiftlint.yml 文件來幫助我們統(tǒng)一編碼規(guī)范了。

總結(jié)

在這一講,我介紹了如何使用 SwiftLint 來統(tǒng)一編碼規(guī)范。特別是其中的only_rules,我們要使用它來定義需要生效的規(guī)則。

[圖片上傳失敗...(image-405d91-1684745180821)]

此外,在制定編碼規(guī)范時,我們還需要注意以下幾點。

首先,所制定的規(guī)范要和業(yè)界標(biāo)準(zhǔn)同步,這能讓新成員接手代碼時,更容易接受而不是反駁。一個建議是,你可以從 SwiftLint 所提供的默認(rèn)規(guī)則開始,畢竟這些規(guī)則都是通過許多人溝通和完善下來的,比你獨(dú)自一人想出來要靠譜得多。

其次,在制定規(guī)范時,重點是提高代碼的可讀性,而不是為了高大上去使用黑魔法或者選擇那些不常用功能等。這樣可以讓團(tuán)隊絕大部分成員更容易理解和遵循這些規(guī)范。

最后要強(qiáng)調(diào)的是,一套編碼規(guī)范是需要不斷迭代和完善的,我建議團(tuán)隊要定時 Retro(Retrospective,敏捷回顧),討論和優(yōu)化這些規(guī)范,讓得大家都有機(jī)會貢獻(xiàn)到規(guī)范中,增加他的認(rèn)同感。這種做法在多團(tuán)隊平行開發(fā)的環(huán)境下特別有效。

思考題:

你所做的團(tuán)隊除了使用 SwiftLint 等工具檢查以外,還使用了哪些手段來保證編碼規(guī)范的統(tǒng)一呢?

請把回答寫到下面的留言區(qū)哦,下一講我將介紹如何使用 Fastlane 執(zhí)行自動化操作。

源碼地址:

swiftlint.yml 文件
https://github.com/lagoueduCol/iOS-linyongjian/blob/main/Moments/.swiftlint.yml


[圖片上傳失敗...(image-ce5bb0-1684745180821)]

《大前端高薪訓(xùn)練營》

12 個月打磨,6 個月訓(xùn)練,優(yōu)秀學(xué)員大廠內(nèi)推,點擊報名,高薪有你!


精選評論

**通:

每次更新能多更新點嗎,2節(jié)也可以啊,一節(jié)感覺不夠看的??

官方客服回復(fù):

因為老師是邊寫邊上線更新的,為了防止斷更,咱們專欄是一周兩更,本專欄是每周二和周四更新,如果覺得了解更多,還可以查看咱們專欄的源碼倉庫,了解下整個新項目

**欽:

oc 有什么好的代碼規(guī)范檢查工具么?

講師回復(fù):

可以使一下 oclint,而且 fastlane 也支持。

**龍:

我看到有swiftlint autocorrect這個命令,但是目前swiftlint是使用cocoapods進(jìn)行安裝的,所以路徑會在 項目根目錄/pods/swiftlint/swiftlint,這種如果多個項目的話,使用起來還得現(xiàn)找路徑然后在執(zhí)行,有沒有什么小tips,技巧可用?

**龍:

請問, 配置好以后, 如何每一次 run 的時候,自動執(zhí)行"swiftlint autocorrect"嗎?

講師回復(fù):

哦,這個可以 Build Phases 上加一個 step 執(zhí)行。

*?。?/h5>

xcode項目本地沒有swiftlint.xml文件好象一樣有效果,怎么做到的?

講師回復(fù):

你說的是 swiftlint.yml 文件吧,我在文件里面講過,假如在項目里面不指定 swiftlint.yml 文件, SwiftLint 會使用一些默認(rèn)的規(guī)則。但是推薦自己配置 swiftlint.yml 文件來保證整個團(tuán)隊都使用一樣的規(guī)則。

**彬:

使用 SwiftLint 之后,連新建文件默認(rèn)產(chǎn)生的 class 定義行 { 下面一行留空行都會警告...... 是真的讓人無語,是不是過濾沒設(shè)置好;提示:Vertical Whitespace after Opening Braces Violation: Don't include vertical whitespace (empty line) after opening braces. (vertical_whitespace_opening_braces) 這樣的錯誤??

講師回復(fù):

假如你需要支持 { 下面一行空行,可以把這個規(guī)則去掉,但是我偏向于保留,因為代碼更緊湊。還有,文章主要給出了如何實現(xiàn)規(guī)范的思路,并不是要求你嚴(yán)格執(zhí)行這些規(guī)則。具體規(guī)范可按照你們團(tuán)隊的具體情況而定。

iOS:

少打了幾個字。。。??moments的yml不在swiftlint執(zhí)行的文件夾內(nèi),我理解就是不在執(zhí)行路徑上。如何起作用的呢?

講師回復(fù):

在 fastlane 里面,我們通過了 config_file 來指定 .swiftlint.yml 文件的路徑。在 Xcode 里面,默認(rèn)會讀取 Moments.xcodeproj 文件夾所在同一層的 .swiftlint.yml 文件。也可以在 --config來讓 Xcode 搜索其他目錄。

**彤:

可以出一個appcode 的相關(guān)使用教程嗎? 有些功能還不是很會用

講師回復(fù):

哦,AppCode 是一個 IDE,打開的時候他會給一些提示,可以看一下。用法和 IntelliJ IDEA 以及 Android Studio 基本一樣,可以 Google 相關(guān)文檔看看。

iOS:

. yml文件按照官方倉庫的提示,在Swiftlint執(zhí)行的路徑添加,不起作用。而moments這個yml不在SwiftLint執(zhí)行的文件,怎么操作?

講師回復(fù):

我不是很理解你的問題,請問你有沒有按照文章的步驟來添加 SwiftLint,我們使用的是 CocoaPods 的 SwiftLint,所以不是很明白 “moments這個yml不在SwiftLint執(zhí)行的文件”。Moments App 的 .swiftlint.yml 放在 Moments/Moments 文件夾下面。如果你使用 VS Code 等工具就能看到。

**祥:

可以詳細(xì)說一下老項目混編轉(zhuǎn)Swift的可行方案嗎,現(xiàn)在網(wǎng)上搜到的都是些沒意義的流水文,我實際上操作起來有很多不兼容的地方,Swift能支持OC的特性,但是OC不支持Swift的特性。

講師回復(fù):

我們在 Swift 1.1 的時候開始混編,我很明白你的痛苦之處呀,坑最多的是正如你說的 Bridging。要講需要一個課程呀,我們后來的一個策略是盡量不要動 OC 的任何代碼(除了新增 Nullability 那些供 Swift 使用以外),新功能全部使用 Swift 來寫并慢慢替換 OC 的代碼。然后盡量不用從 OC 引用 Swift 的代碼,如果循環(huán)引用,以后代碼很難維護(hù),而且為了兼容性, Swift 的代碼也學(xué)得像 OC。

**4349:

老師有沒有班級微信群,拉一個一起學(xué)習(xí)

官方客服回復(fù):

可以通過課程下方的“添加專屬社群”來加入班級社群哈~

**西瓜:

怎么讓SwiftLint也檢查Designkit

講師回復(fù):

我給你一個提示吧,使用的是 included,注意路徑的選擇,如果你做出來,來個 PR?

**0593:

短!

**澤:

老師您好,是不是OC使用OCLint

講師回復(fù):

是呀,但是我現(xiàn)在已經(jīng)不怎樣寫 OC 了,以前寫 OC 的時候,我使用 AppCode,基本上生成的代碼都很標(biāo)準(zhǔn)了。

?著作權(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)容