代碼注釋中使用 Markdown 并生成在線文檔

背景:如果代碼注釋可以生成如蘋果官方文檔樣式的在線文檔,并能使用 Markdown 語法進(jìn)行編輯,將是一件極好的事情,于是發(fā)現(xiàn)了 這篇專題。進(jìn)行精簡之后就有了本文。IDE 要求 Xcode7 及以上

代碼注釋的重要性

通過寫注釋,你可以:

  • 詳細(xì)介紹工程中、方法屬性所表達(dá)的意思
  • 高亮顯示方法中的參數(shù)返回值
  • 在幾個(gè)月后再去看你項(xiàng)目,可以無障礙的知道里面的方法是用來做什么的,屬性又代表了什么意思等
  • 當(dāng)你把代碼分享出去或制作成庫時(shí),開發(fā)者可以方便的使用你的代碼
  • 使用工具比如:Jazzy,生成看上去很專業(yè)的使用指南,就像蘋果官方文檔一樣

可以通過3種方式,來預(yù)覽和查看代碼文檔:

  • 按住 option/alt 按鈕,點(diǎn)擊某個(gè)屬性,方法,類名,就會(huì)彈出 Quick Help 快速預(yù)覽
  • 光標(biāo)移到某個(gè)屬性方法,類名,打開 Xcode 右邊工具欄,在 Quick Help 中查看
  • 使用第三方工具,生成一份指南。比如工具 Jazzy ,它可以把所有的注釋生成網(wǎng)頁,然后把這些網(wǎng)頁組成一個(gè)單獨(dú)的網(wǎng)站,并保存到項(xiàng)目的一個(gè)子目錄中

Markdown 基本語法

請參考 Markdown

開始使用 Markdown 語法

你可以對項(xiàng)目中的屬性,方法,,結(jié)構(gòu)體,枚舉,協(xié)議,擴(kuò)展以及任何代碼結(jié)構(gòu)或?qū)嶓w進(jìn)行注釋。

注釋塊寫在某個(gè)聲明的上面,或者某個(gè)實(shí)體的頭一行。每一行以3個(gè)斜杠(///)開頭,或者所有的注釋都寫在下面這個(gè)塊中:

/**

*/
  • 我們來看第一個(gè)使用 Markdown 語法的代碼片段,新建一個(gè) Playground,加入以下代碼:
/// This is an **awesome** documentation line for a really *useful* variable
var someVar = "This is a variable"

預(yù)覽一下這個(gè)變量,預(yù)覽效果如下圖:


請注意單詞 awesome 是加粗的,因?yàn)樗粌蓚€(gè)星號對包圍。而單詞 useful 是斜體,因?yàn)樗灰粋€(gè)星號對包圍。

  • 我們再來看一個(gè)例子,給函數(shù)添加注釋,添加以下代碼:
/**
    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
    }
}

然后,按住 option 鍵,點(diǎn)擊這個(gè)函數(shù)名稱,就會(huì)彈出 Quick Help,預(yù)覽效果如下圖:


在注釋中,我們使用了兩個(gè)新元素,headerordered list ,同時(shí)也使用了加粗和斜體。只要你按著 Markdown 的語法要求,使用這些特殊的字符,就可以很容易的寫出富文本的文檔了。下圖是在 Xcode 右側(cè)工具欄的 Quick Help 中展示文檔的效果:

  • 接下來,我們嘗試在注釋中加入 代碼塊,為了展示 代碼塊 的區(qū)域效果,需要使用符號 (`) 。在 Playground 中添加以下代碼:
/**
    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
}

預(yù)覽效果如下圖:


  • 最后,我們給 enum 添加注釋,每一個(gè) case 都有相應(yīng)的注釋,然后在另外一個(gè)函數(shù)中使用它。添加如下代碼:
/**
    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.Center
    print(alignmentOption)
}

當(dāng)我們使用枚舉 AlignmentOptions 中的某一個(gè) case 的時(shí)候,Xcode 會(huì)自動(dòng)顯示相對應(yīng)的注釋,如圖所示:

文檔中使用關(guān)鍵字

有了富文本,那么再加上些 keywords 會(huì)使得文檔更加完美。Xcode 會(huì)根據(jù) keyword 渲染出對應(yīng)的格式(同樣適用于第三方庫生成的文檔),比如高亮顯示 參數(shù)、返回值、某個(gè)類的作者、函數(shù)版本等。 keyword 有很多,我們只介紹最常用的幾個(gè)

  • 關(guān)鍵字 parameter(不區(qū)分大小寫)。

在 Playground 中添加以下代碼:

/**
    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 fullname.
    - parameter lastname: The last part of the fullname.
 
 */
func createFullName(firstname: String, lastname: String) {
    
    let fullname = "\(firstname) \(lastname)"
    print(fullname)
}

文檔預(yù)覽效果如下圖:

  • 關(guān)鍵字 Returns(記得加上冒號)。

修改上面的代碼,返回 full name,文檔中添加關(guān)鍵字 Returns 如下:

/**
    This is an extremely complicated method that returns the full name.
     
    - Parameter firstname: The first part of the fullname.
    - parameter lastname: The last part of the fullname.
    - Returns: The full name as a string value.
 */
func returnFullName(firstname: String, lastname: String) -> String{
    
    return "\(firstname) \(lastname)"
}

文檔預(yù)覽效果如下圖:


  • 以上兩個(gè)關(guān)鍵字 parameterReturns 是最常用的。

  • 關(guān)鍵字 RemarkSeeAlso。

寫一個(gè)函數(shù),把一個(gè) full name,拆分為兩部分:firstnamelastname,并返回。代碼如下:

/**
    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 contatenates the first and last name into a full name.
    - SeeAlso: `returnFullName(_:lastname:)`
 */
func breakFullName(fullname: String) -> (firstname: String, lastname: String) {
    
    let namesTuple = fullname.componentsSeparatedByString(" ")
    return (namesTuple[0],namesTuple[1])
}

Remark 在文檔中高亮顯示(吸引開發(fā)者注意),介紹代碼中重要的或特殊的地方。SeeAlso 也會(huì)高亮顯示,其主要是用來延伸到其他地方,或者提供一個(gè) URL 鏈接,上面的代碼中,引用了函數(shù) returnFullName(_:lastname:)。文檔預(yù)覽效果如下:

  • 關(guān)鍵字 PreconditionRequires。

假設(shè)上面的函數(shù)是某個(gè)庫的一部分,為了讓開發(fā)者正確使用這個(gè)函數(shù),需要讓開發(fā)者知道兩點(diǎn)要求:

  • 參數(shù) fullname 不能為 nil
  • fullname 包含 fistnamelastname,它們之間用空格隔開

更新上面的文檔:

/**
    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 contatenates the first and last name into a full name.
    - SeeAlso: `returnFullName(_: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 namesTuple = fullname.componentsSeparatedByString(" ")
    return (namesTuple[0],namesTuple[1])
}

預(yù)覽文檔效果如下:


  • 關(guān)鍵字 Todo。

    在將來的某個(gè)版本,也許會(huì)去完善這個(gè)功能,比如可支持 middle name。那么用 Todo 來介紹:

 - Todo: Suppotr middle name in the next version.

還有很多其它的關(guān)鍵字,比如:warnings, version, author, notes。把它們都加進(jìn)去,然后看一下效果:

/**
    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 contatenates the first and last name into a full name.
    - SeeAlso: `returnFullName(_: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` parameter.
    - Version: 1.0
    - Author: Cook
    - Note: Too much documentation for such a small function.
 */
func breakFullName(fullname: String) -> (firstname: String, lastname: String) {
    
    let namesTuple = fullname.componentsSeparatedByString(" ")
    return (namesTuple[0],namesTuple[1])
}

生成在線文檔

使用 Jazzy 來制作在線文檔。Jazzy 這個(gè)工具非常棒,可以生成和蘋果官方文檔一樣的在線文檔,支持 swift (默認(rèn)) 和 OC。詳細(xì)介紹請看 github

  • 安裝 Jazzy
    打開終端,輸入:
sudo gem install jazzy

根據(jù)提示輸入密碼,進(jìn)行安裝。如果安裝失敗,請查看這個(gè) issue。成功之后會(huì)有下圖這樣類似的信息:

  • 你需要一個(gè)項(xiàng)目
    你需要一個(gè)項(xiàng)目進(jìn)行文檔轉(zhuǎn)換,可以下載 這個(gè)項(xiàng)目 作為轉(zhuǎn)換的對象,里面包含有簡單的文檔說明。

  • 開始生成文檔
    cd 到剛才下載的文件目錄

cd the_path_of_your_project_folder

由于項(xiàng)目中都是用的默認(rèn)internal 屬性,為了包含所有的內(nèi)容,在終端輸入:

jazzy --min-acl internal

回車,成功之后的樣子如下圖:


  • 你可以使用 jazzy -help 來查看所有可以使用的適合你的參數(shù)。

  • 最后說明
    生成的文檔會(huì)保存在項(xiàng)目目錄下 docs 文件夾中。進(jìn)入這個(gè)文件夾,雙擊打開 index.html,就可以在網(wǎng)頁上查看生成的文檔了:

  • 總結(jié)
    文檔在一個(gè)項(xiàng)目中的地位是和重要的,尤其是多人合作開發(fā)。如果一段文檔不能清晰的表達(dá)代碼意思,對于開發(fā)者的效率來說是致命的。故,通過此文章,來鼓勵(lì) IT 人員盡可能詳細(xì)的書寫文檔。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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