作者:Gabriel Theodoropoulos,原文鏈接,原文日期:2016-05-12
譯者:小鐵匠Linus;校對:Channe;定稿:numbbbbb
在 Xcode 7 的所有功能中,有一個很特別:它給編寫代碼文檔提供了一個更好的方法。隨著 Xcode 7 的更新,開發者可以使用 Markdown 語法書寫富文本格式的代碼文檔,而且可以結合特定的關鍵詞來指明特殊部分(如參數,函數返回結果等)。作為新支持的 Markdown 文檔樣式,它具有以下幾點優勢:文本樣式的自定義程度更高,更加靈活,當然也更有趣。然而,如果你仍然對原來的文本樣式感興趣的話,也可以看以前那篇教程。
對每個開發者來說,代碼文檔是開發中非常重要的一件事。即使它看上去會拖慢開發進度,但實際上它是開發中不可或缺的一部分。我不反對給每個屬性、函數、類、結構體等書寫正確且全面的文檔,但這并不是一件容易的事。不過,你可以通過以下幾點來編寫適當的文檔:
描述各個屬性、函數和類的真正用途。此外,最好能在需要注意的地方高亮函數的具體使用情況、用例或需求。
高亮函數的輸入和輸出(參數和返回值)。
為了幾個月后再打開項目還能清晰地記得每個函數做了什么,每個屬性是為了什么。
當你把代碼共享或做成 lib 時,一定要讓其他開發者能輕松地理解怎么使用你的代碼。
使用工具制作具有專業外觀的使用手冊(比如:使用 Jazzy)。
你在 Xcode 里寫的代碼文檔能被預覽,也可以用以下的三種方法訪問:
按住 Option/Alt 鍵點擊屬性名、方法名或類名等,會彈出快速預覽(Quick Look preview)。
光標移動到屬性名、方法名或類名上,打開快速幫助(Quick Help Inspector)進行查看。
使用第三方工具可以產生使用手冊。比如,Jazzy 就是這樣一款工具,我們稍后會講到。通過使用它,可以在你工程的文件夾里生成一個集成了所有你寫的代碼文檔的網頁。
代碼文檔不是很死板的東西;它可以根據各自實體(屬性、方法、類、結構、枚舉)的修改而改變。如果你沒有在實現一個新的實體時添加文檔的話,那么幾乎可以肯定,你永遠不會去添加文檔了。因此,試著養成一個這樣的習慣:在合適的時間點去書寫代碼文檔,并在新的實體實現后能花時間去更新文檔。
Markdown 基礎語法
為了能更好地使用新的文檔樣式,對 Markdown 語法有一個基本的認識是很重要的。如果已經對這部分有充分的了解的話,可以跳過這一章,直接看下一章。你可以在網絡上找到關于 Markdown 的很多信息,比如這里還有這里都能找到。
盡管你能找到關于 Markdown 語法的其他資源,但是我覺得至少要講一下基礎語法。我的目的當然不是要提供一整個 Markdown 使用指南,只是為了呈現特定語法的常見用法。
因此,你大概知道(可能現在才知道)Markdown 語法是由特殊字符來格式化文本、添加資源(鏈接和圖片)以及添加文本塊(有序或無序列表,代碼塊等)。雖然這些字符很容易記住,但是還是需要經常上網查查或看看下面列出來的。有必要在這里說一下,如果你習慣了 Markdown 語法(其實很容易就做到了),然后通過使用合適的編輯器就可以生成不同格式的文檔了,例如:HTML 頁面、PDF 文檔等等。說到 HTML 頁面,Markdown 支持內聯 HTML,也就是說,你可以直接把 HTML 標簽寫到文本里,這些標簽都會被渲染。然而,使用 HTML 并不是 Markdown 的本質,因此我們還是回到 Markdown 自己的語法吧。
以下列出了最常用的 Markdown 語法:
- #text#:文本標題,相當于 HTML 中的 <H1> 標簽。兩個 # 則對應 <H2> 標簽,以此類推,直到 <h6> 標簽。末尾的 # 可以省略。
- **text**:使文本具有加粗的效果。
- *text*:使文本具有斜體的效果。
- * text:使文本成為一個無序列表的元素,值得注意的是,有個 * 后面需要有一個空格。同樣,可以使用 + 或 - 實現這個的功能。
- text:使文本成為一個有序列表的元素。
-
[linked text](http://some-url.com)
:使文本成為可以點擊的超鏈接。 - > text:創建一個塊引用。
- 使用 4 個空格或 1 個 tab 來縮進所寫的代碼塊,等價于 HTML 中的 <pre></pre> 標簽??梢岳^續使用 4 個空格或 1 個 tab 來添加另一個縮進。
- 如果不想使用空格或 tab 的話,可以使用 ` 。比如, `var myProperty` 會顯示成
var myProperty
。 - 另一種創建代碼塊的方法是添加 4 個 `,并從下一行開始寫具體的代碼,最后添加 4 個 ` 表示結束。
- 反斜杠修飾 Markdown 的特殊字符就可以避免 Markdown 語法的解析了。比如,
\**this\**
就不會產生加粗的效果。
以上這些是 Markdown 語法中比較重要的部分。雖然,Markdown 語法中還有很多額外的細節可以深究。但是,以上提供的這些已經足夠你開始使用 Markdown 了。
如果你發現 Markdown 還蠻有意思的話,你可以下載一個編輯器具體嘗試一下。使用編輯器,你可以實時地看到你所寫的文本在轉化成 HTML 后的效果。
關于編輯器:你可以嘗試以下這些 Markdown 編輯器:StackEdit,Typora,Macdown,Focused 和 Ulysses。
使用 Markdown
在編寫任何 Swift 中實體的文檔時,有些規則是一定要遵守的。你可以為屬性(變量和常量)、方法、函數、類、結構體、枚舉、協議、擴展和其他代碼結構或實體編寫代碼文檔。針對實體的每個文檔塊都要寫在定義或頭文件前面,且以 3 個斜線(///)或以下面的形式開頭:
/**
*/
雖然 // 也被視為注釋,但是這種語法會被 Xcode 忽略,而不產生對應的代碼文檔。你可以在各種代碼塊中使用 // 來注釋,但是正如我上一句說的,這并不會產生對應的代碼文檔。(譯者注:老外就是這么啰嗦,怪我咯~)
讓我們來看一個簡單的例子熟悉一下 Markdown 語法吧。在下面的代碼塊中,我們為一個屬性添加了一行可以產生代碼文檔的注釋。我建議你可以打開 Xcode 中 Playground 來試試本文中提到的所有例子。(校對注:為了保持和截圖一致,下面的注釋沒有翻譯)
/// This is an **awesome** documentation line for a really *useful* variable.
var someVar = "This is a variable"
以上寫的代碼文檔會在 Xcode 中呈現以下效果:
值得注意的是,單詞 “awesome” 是加粗的,而 “useful” 是斜體的。前一個是由 ** 包含,后一個則由 * 包含產生的。
讓我們來對函數來做另一個例子:
/**
It calculates and returns the outcome of the division of the two parameters.
## Important Notes ##
1. Both parameters are **double** numbers.
2. For a proper result the second parameter *must be other than 0*.
3. If the second parameter is 0 then the function will return nil.
*/
func performDivision(number1: Double, number2: Double) -> Double! {
if number2 != 0 {
return number1 / number2
}
else {
return nil
}
}
拷貝以上代碼到 playground 中,再按住 Option 鍵點擊函數名,就會彈出一個快速幫助(Quick Help),如下圖:
這里我們使用了兩個新的 Markdown 元素,標題和有序列表。同時,也有加粗和斜體的文本??梢钥吹降氖?,簡簡單單地使用了 Markdown 語法中的特殊字符就可以生成如此復雜的富文本代碼文檔。以下是快速幫助欄(Quick Help Inspector)的截圖:
下面例子中,我們為函數添加一個代碼文檔中的代碼塊。值得注意的是,除了創建了一個代碼塊,我們還用` 標記了內聯函數的名稱。
/**
It doubles the value given as a parameter.
### Usage Example: ###`
let single = 5
let double = doubleValue(single)
print(double)
`
* Use the `doubleValue(_:)` function to get the double value of any number.
* Only ***Int*** properties are allowed.
*/
func doubleValue(value: Int) -> Int {
return value * 2
}
以下是最終效果:
最后,讓我們來為枚舉添加代碼文檔,并在其他函數中使用。這個例子中有趣的是每個枚舉類型的代碼文檔:
/**
My own alignment options.`
case Left
case Center
case Right
`
*/
enum AlignmentOptions {
/// It aligns the text on the Left side.
case Left
/// It aligns the text on the Center.
case Center
/// It aligns the text on the Right side.
case Right
}
func doSomething() {
var alignmentOption: AlignmentOptions!
alignmentOption = AlignmentOptions.Left
}
現在,當你使用到這個枚舉時,Xcode 就會顯示之前你寫的對應的代碼文檔:
使用關鍵字
使用 Markdown 語法只是為 Swift 代碼添加代碼文檔的一個好處。顯而易見,富文本格式很強大,可以展示精美的文檔內容,但是下面要介紹另一個很厲害的關鍵字。
當你使用關鍵字時,Xcode 會在渲染代碼文檔時自動應用對應的文本格式(其他第三方庫也是這么做的)。關鍵字可以很方便地指出代碼結構中常見的部分,然后區分出來。舉個例子,有很多關鍵字可以高亮方法的參數、返回值、類的作者或方法的版本。這個關鍵字的列表還挺長的,然而并不是每個關鍵字都會頻繁使用,有些基本沒人用。不過大多數常見的關鍵字最好還是記在腦子里,至于其它的可以在需要時再去查。
正如上面說的,是時候通過幾個簡單的例子來說明關鍵字的用法了。首先來說一下,方法或函數中接收的參數吧:
/**
This is an extremely complicated method that concatenates the first and last name and produces the full name.
- Parameter firstname: The first part of the full name.
- Parameter lastname: The last part of the fullname.
*/
func createFullName(firstname: String, lastname: String) {
let fullname = "\(firstname) \(lastname)"
print(fullname)
}
以上代碼會顯示成這樣:
值得注意的是關鍵字前的 - 號以及與關鍵字中間的空格。后面跟隨的是具體的參數名。你必須對所有的參數都書寫對應的描述文字。
現在讓我們修改一下上面的函數,將這個函數返回一個字符串而不只是打印出來。為了實現這個,我們添加了一個可以描述函數返回值的關鍵字:
/**
This is an extremely complicated method that concatenates the first and last name and produces the full name.
- Parameter firstname: The first part of the full name.
- Parameter lastname: The last part of the fullname.
- Returns: The full name as a string value.
*/
func createFullName(firstname: String, lastname: String) -> String {
return "\(firstname) \(lastname)"
}
顯示結果是這樣的:
以上這兩個關鍵字(Parameter 和 Returns)是會用的比較頻繁的。接下來的這個函數實現了與上一個函數完全相反的功能,將全名拆分成姓和名:
/**
Another complicated function.
- Parameter fullname: The fullname that will be broken into its parts.
- Returns: A *tuple* with the first and last name.
- Remark:
There's a counterpart function that concatenates the first and last name into a full name.
- SeeAlso: `createFullName(_:lastname:)`
*/
func breakFullName(fullname: String) -> (firstname: String, lastname: String) {
let fullnameInPieces = fullname.componentsSeparatedByString(" ")
return (fullnameInPieces[0], fullnameInPieces[1])
}
上面新出現的兩個關鍵字是 Remark 和 SeeAlso。通過使用 Remark,你可以高亮你想要引起讀者注意的地方。關鍵字 SeeAlso 可以引用代碼的其它部分(比如,我們這個例子中是引用了前一個函數)或提供一個 URL。Xcode 中的快速幫助(Quick Help)會顯示如下:
試著想象一下,上面的這個函數會分享給其他開發者使用。你肯定希望所有使用這個函數的人都能知道:參數 fullname
不能是空的,且姓和名要包含在全名里,并以空格分隔,這樣函數才能正確調用。為了實現這個,你需要使用另外兩個關鍵字 Precondition 和 Requires。讓我們來對應的更新下上面的那個函數:
/**
Another complicated function.
- Parameter fullname: The fullname that will be broken into its parts.
- Returns: A *tuple* with the first and last name.
- Remark:
There's a counterpart function that concatenates the first and last name into a full name.
- SeeAlso: `createFullName(_:lastname:)`
- Precondition: `fullname` should not be nil.
- Requires: Both first and last name should be parts of the full name, separated with a *space character*.
*/
func breakFullName(fullname: String) -> (firstname: String, lastname: String) {
let fullnameInPieces = fullname.componentsSeparatedByString(" ")
return (fullnameInPieces[0], fullnameInPieces[1])
}
展望未來,你可能會樂意記下未來計劃的變更:
- Todo: Support middle name in the next version.
你甚至可以在寫代碼文檔時,添加 warnings、 version、author 和 notes:
/**
Another complicated function.
- Parameter fullname: The fullname that will be broken into its parts.
- Returns: A *tuple* with the first and last name.
- Remark:
There's a counterpart function that concatenates the first and last name into a full name.
- SeeAlso: `createFullName(_:lastname:)`
- Precondition: `fullname` should not be nil.
- Requires: Both first and last name should be parts of the full name, separated with a *space character*.
- Todo: Support middle name in the next version.
- Warning: A wonderful **crash** will be the result of a `nil` argument.
- Version: 1.1
- Author: Myself Only
- Note: Too much documentation for such a small function.
*/
func breakFullName(fullname: String) -> (firstname: String, lastname: String) {
let fullnameInPieces = fullname.componentsSeparatedByString(" ")
return (fullnameInPieces[0], fullnameInPieces[1])
}
以下是顯示結果:
看了上面這么多例子,你應該能理解關鍵字的詳細程度完全是由你確定的。代碼中重要的部分(比如,上面拿來舉例子的函數)要有具體的代碼文檔,而次要的部分只寫基本的文檔即可。
Apple 提供了一個所有代碼文檔中可能用到的關鍵字頁面,你如果點了下面提到的超鏈接,你可以看到每個關鍵字采用 Markdown 語法的具體使用指南。走過路過,不要錯過了,進去瞧一瞧。
使用 Jazzy 產生代碼文檔
Jazzy 是一款可以為 Swift 和 Objective-C 代碼產生具有 Apple 風格的代碼文檔工具。事實上,Jazzy 會為你創建一個鏈接所有代碼文檔的獨立網頁。它是一款命令行工具,但還是很容易使用的。
我并不打算介紹 Jazzy 的具體使用方法;只需要訪問它的 GitHub 頁面,你就能找到所有你想要的信息了,包括使用要求和安裝方法。安裝過程真的很簡單,你所有要做的如下:
- 打開“終端”
- 輸入“sudo gem install jazzy”
- 輸入密碼
- 等待
為了方便你嘗試使用 Jazzy,我已經準備好了一個工程,你可以在這里下載。這個工程很簡單,它就是基于之前提到的例子寫的,即組合姓和名成全名以及全名分割成姓和名。
在這個工程里,我已經添加了和之前例子中類似的代碼文檔。即使這個工程只是為了演示,但是不管是用在什么場合,它不僅能支持類、方法和屬性,還能支持結構體、枚舉、擴展、協議等等。
假設你現在已經下載了那個工程,讓我們來看看 Jazzy 到底是怎么用的。一開始,使用 cd
命令將目錄切換到工程對應的目錄:
cd path_to_project_folder
簡單地輸入 Jazzy
然后敲回車等著,然而,這樣并不能將類或其他沒有標注為 public 的結構寫入代碼文檔。因此,如果你想要包含所有的實體,就輸入一下:
jazzy --min-acl internal
另外,如果你用的不是 Swift 的最新版本,發現使用 Jazzy 后沒有效果的話,你可以通過以下命令來指定你的 Xcode 支持的 Swift 版本:
jazzy --swift-version 2.1.1 --min-acl internal
我強烈建議你輸入 jazzy -help
看看所有你使用 Jazzy 時可能使用到的參數。當然,你完全可以根據自己的喜好來得到最終的結果。
以下是你生成代碼文檔頁面時會看到的:
默認輸出的文件夾位于工程的根目錄(你也可以更改輸出路徑),叫 docs。
使用 Finder 進入到對應路徑,在瀏覽器中打開 index.html。你立即就會發現,默認生成的頁面風格和 Apple 官方文檔是非常相似的。在頁面里到處點擊看看,看看具體顯示的代碼文檔。接下來,就嘗試在你自己的工程中使用吧。
總結
為代碼寫文檔是一件必要且重要的事,但是開發者往往因為缺乏時間而放棄了。當項目臨近交付時間或在短短時間內還有很多 bug 要修復,這就很難有機會為項目的每一個部分寫出合適的文檔。然而,我希望通過這篇文檔,你可以意識到代碼文檔的重要性,并試著盡量寫一下代碼文檔。你不需要寫下所有的細節,但你至少要為代碼中的重要部分增加高亮,方便其他開發者或以后你自己繼續在這個代碼基礎上進行修改。因此,你不要忘了還有一款專業的代碼文檔生成工具 Jazzy 可以使用。也許這可以成為你寫代碼文檔的動力吧!
本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問 http://swift.gg。