作者:旷明,iOS Dev。GitHub: KeithBird Twitter: @KeithBirdKTH Blog: Kth App: 语法树
审核:示晔,iOS 开发。Swift 和 NodeJS 爱好者
本文基于 Session 10166 10167 10235 10236 梳理
作者将本教程和部分 WWDC 中的代码实践,通过 DocC 技术编译成教程放在 WWDocC 代码库中
前言
苹果在 WWDC 视频上投入的精力有目共睹,但留给开发者的官方文档常常惨不忍睹,甚至于有一个专门的网站统计了 No Overview Available 的苹果文档。据调查只有 30% 左右的 iOS 开发者通过官方文档学习 API,Paul Hudson 也在 WWDC 21 前许愿写下 Reimagining Apple’s documentation 一文。
但 SwiftUI Tutorials 和 Catalyst Tutorials 依然如同两股清流,是开发者们在文档沙漠中的绿洲。苹果很明显没有时间为每项技术提供如此生动的教程,于是将这个能力通过 DocC (Documentation Compiler) 开放给了开发者们(和 iPad 没有计算器有异曲同工之妙)。当然 DocC 也可以用来给自己的开源项目编写文档,以加快项目的推广和建设。
文档的编译
DocC 通过编译源码中的文档注释和 DocC 专属的文档文件生成文档的文本内容。文本内容通过我们接下来要编写的链接,和源码编译后提取的接口结构,组织在一起,形成最终的文档。
通过点击菜单栏的 Product > Build Documentation 可以完成编译。也可以将此步骤添加到 Build 过程中,只需在 Building Settings 的 Documentation Compiler 中,将 Build Documentation during 'Build' 设为 Yes。想了解如何使用命令行编译,可以查看「文档的发布」一节。
编译文档注释
Xcode 首先会编译代码源文件,并提取文档注释中的公共 API 信息(如概要、参数说明、返回值说明等),以生成一些文档内容,作为生产 DocC Archive 的部分材料。因此,在默认情况下,DocC 仅靠编译源码,就可以生成按接口类型和接口结构组织的文档。
编译文档文件
当你有如下需求时,可以考虑使用 documentation catalog 为文档注释进行补充:
- 通过文档首页介绍框架和主要接口。
- 需要自定义组织文档的结构。
- 通过文章详细说明开源框架。
- 通过教程逐步指导最佳实践。
- 文档中包含图片视频等内容。
你可以新建一个 documentation catalog,将其放到 Swift package 中与源码相同的目录下。也可以在新建 Swift framework project 时,勾选 Include Documentation。
DocC 将会结合 Swift compiler 中的公共 API 信息,和 documentation catalog 中的文档内容,以生成更加丰富的 DocC Archive 文档文件。
注释的格式
按住 Command 键点击接口名称并选择 Add Documentation 可以自动生成文档注释的模版。你可以在模版中依次填写接口的概要、说明、参数说明、返回值说明、抛出说明等内容。这些内容的编写格式为 markup,markup 会在文档的编写中多次使用,可以在 Formatting Your Documentation Content 一文中进行学习。
/// Eat the provided specialty sloth food.
///
/// Sloths love to eat while they move very slowly through their rainforest
/// habitats. They're especially happy to consume leaves and twigs, which they
/// digest over long periods of time, mostly while they sleep.
///
/// When they eat food, a sloth's `energyLevel` increases by the food's `energy`.
///
/// - Parameters:
/// - food: The food for the sloth to eat.
/// - quantity: The quantity of the food for the sloth to eat.
///
/// - Returns: The sloth's energy level after eating.
///
/// - Throws: `SlothError.tooMuchFood` if the quantity is more than 100.
mutating public func eat(_ food: Food, quantity: Int) throws -> Int {...}
通过编写上面的文档注释并进行编译,你可以在对应的接口文档中看到以下信息:
也可以通过 Quick Help (optiong + 点击接口名弹出) 查看:
文档的编写
DocC 中的文档一共分为三类:在官方文档中被普遍使用,用于具体介绍接口的参考文档(Reference)。形式更加灵活自由,用于介绍框架背后构造(如不同组件之间的联系)的文章(Articles)。通过交互式的逐步指导,帮助用户完成最佳实践的教程(Tutorials)。
我们首先从参考文档中的主页开始:
编写内容
默认情况下,DocC 会通过列出公共接口,并按类型进行分组来形成主页,作为文档的入口。
但我们也可以通过以下步骤进行自定义。首先所有 DocC 文件必须在与项目同名的 documentation catalog 中才有效,我们可以在其中新建一个 Documentation 中的 Empty 文件作为首页:
同样用项目名给这个 .md 文件重命名,且标题 ```` 中的内容也要是项目名,这样 Xcode 才能在编译时将它们关联起来。标题下方是一段概要,接着你可以用 markup 语法为文档的主页添加文字、代码、图片、视频等内容。
# ``SlothCreator``
Catalog sloths you find in nature and create new adorable virtual sloths.
重写结构
在我们刚刚编写的文档内容之后,你会发现公共接口默认按类型罗列在 Topic 主题中,如果你希望按照自己的想法重新组织,可以在主页文件中追加 Topic 部分:
其中 ### 用于给每个分组命名。- <doc:/tutorials/SlothCreator> 用于链接 tutorials 目录下名为 SlothCreator 的文件。```` 用于链接到对应的接口文档,其内容必须是接口的完整路径,如 ``SlothCreator/Sloth/eat(_:quantity:)``。
Topics 被重构后,可以发现左侧导航栏的结构也随之改变:
如果自行编写的 Topics 中遗漏了部分公共接口或 DocC 的文章和教程目录等,它们依旧会以默认(按类型分组)的方式追加到自定义的结构之后,以保证文档的完整性。
除了主页可以自定义,各个接口的参考文档同样可以自定义。只需新建一个 Documentation 中的 Extension File,将文件名改为接口名,并在第一行 ```` 中填写接口的完整路径。文档内容和 Topics 的编写方式与主页相同,它们会被添加到文档注释生成的文档内容之后。
# ``SlothCreator/Sloth``
## Topics
### Creating a Sloth
- ``init(name:color:power:)``
- ``SlothGenerator``
...
需要注意的是标题 # 后面的 ```` 用于给 Xcode以提示:对应的接口名需要被链接到本篇文档。正文中 - 后面的 ```` 用于产生一个链接以跳转到对应的接口文档。接口内部的成员如果没有被完整列出,也会像主页一样按默认方式追加到末尾。
覆盖注释
Extension File 中的内容默认会追加到文档注释编译生成的内容之后,但在某些时候我们希望完全重写参考文档,这时我们需要在标题下方注明采用覆盖方式:
# ``SlothCreator/Sloth``
@Metadata {
@DocumentationExtension(mergeBehavior: override)
}
此处内容会覆盖源码生成的概要。
## Overview
此处内容会覆盖源码生成的综述。
...
注意,这一参数的改变并不会影响 Topics 中的内容。
补充性文章
文档以接口为标题进行编写,结构相对死板。而文章则是一种更加灵活的方式,可以对框架的其他方面进行补充说明。你可以通过新建一个 Documentation 中的 Article File 来创建文章。
文章默认会作为结构中的最顶层出现在主页和导航栏中。因此,与我们之前编写的内容不同的是,文章的标题是常规内容而不是引用。对应的,其文件名也没有特殊要求,只有在该文章被引用时才会用到。文章的正文内容同样使用 markup 进行编写,同样可以在末尾追加 Topics 以组织文档结构。
# Getting Started with Sloths
Create a sloth and assign personality traits and abilities.
## Overview
Sloths are complex creatures that require careful creation and a suitable
habitat.
...
## Topics
### Essentials
- <doc:/tutorials/SlothCreator>
- ``Sloth``
交互式教程
交互式教程的效果难以言传,没有体验过的读者可以参考 SwiftUI Tutorials 和 Catalyst Tutorials。教程同时也是 DocC 中的一大亮点,它主要由教程目录和教程页两部分组成:
文件格式
教程需要被建立在 documentation catalog 之中。你可以通过新建 Documentation 中的 Tutorial Table of Contents 和 Tutorial File 来创建教程目录和教程页,它们都是 .tutorial 文件。只有教程目录能跳转到教程页,所以即使只有一个教程也必须编写教程目录。默认情况下 documentation catalog 会包含一个 Resources 文件夹,用于储存 DocC 的文档、文章、教程中所使用到的图片、视频、代码等资源。
如图所示,markup 文件中使用的图片有官方的命名建议:
其中只有图片名和拓展名为必选项,~dark 表示在暗黑模式下会使用该图片,@ 之后所接的内容用于标明不同显示比例的设备所使用的图片。采用上述命名方式,只需在 markup 文件中填写图片名,DocC 便会自动在文档中动态采用最佳版本的图片。[ ] 中是对图片内容的描述,用于给视障人士提供语音提示。

代码资源没有官方命名规范,由于其主要用在逐步教程中,建议将其命名为 教程名-章节名-步骤数.swift。
目录编写
在新建教程目录后 Xcode 会自动填写模版,以帮助开发者入门。目录文件名和 @Tutorials(name: ) 中的内容一般为项目名。
@Intro 指令后紧接着目录的标题,教程的概述,和一张封面图片。预计用时和 Get Started 按钮是基于之后提供的教程页信息自动生成的。
@Chapter 指令用于分类和组织教程,包括了篇名,篇目图片,教程引用。其中 @TutorialReference 可以用文件名链接到对应的教程页。
一个教程目录(@Tutorials)包含一个介绍(@Intro)和多个篇目(@Chapter),一个篇目又可以包含多个教程页的引用(@TutorialReference)。
教程编写
一个教程页(@Tutorial)包含一个介绍(@Intro)和多个章节(@Section),一个章节只能包含一个步骤集(@Steps),步骤集之下的步骤(@Step)是最小的结构。
教程页的文件名没有特殊要求,仅在链接时使用。@Tutorial(time: ) 中填写浏览该教程页的预计用时。该教程所处的篇目名(SlothCreator Essentials)会自动显示。教程页 @Intro 的格式和目录的一样。
教程页下的结构为章节(@Section)。章节用 @ContenAndMedia 来显示简介,并且可以通过填写 (layout: ) 中的参数,调整图片等媒体与文字内容的排版方式。
@Step 中包含一段在左边逐步展示的说明,开发者希望文档中显示的文件名,代码段真正的文件名,和一张预览图:
可以看出预览图并非代码编译生成的,需要开发者提前截图保存。建议将源码文件和预览图片规范命名,并分组放到之前提到的 Resource 文件夹中,以免产生混乱。
@Code 并不是必须的,@Step 也可以写成这样:
@Step {
Create a new project using the iOS App template.
@Image(source: image-Tutorial1-Section1-Step1.png, alt: "")
}
效果如下:
需要注意的是 @Image(source: image.png, alt: "") 中的 alt 参数是不可以省略的,上面的图片中的示例代码由于缺少该参数会被 Xcode 报错。alt 的全称是 alternative text,这段文字将会被读屏器 VoiceOver 朗读,用于给视障人士提供帮助。
文档的发布
Xcode 编译完文档之后会产生一个 documentation archive 文件,你可以将该文件直接从文档中导出:
也可以使用命令行工具编译到指定地址:
xcodebuild docbuild
-scheme SlothCreator
-derivedDataPath ~/Desktop/SlothCreatorBuild
在编译过程中,Xcode 会在目标地址生成数量众多的文件,可以使用下面的指令进行定位:
find ~/Desktop/SlothCreatorBuild
-type d -name '*.doccarchive'
只需将 .doccarchive 文件包发送给其他开发者,对方就可以用 Xcode 将其打开以查看文档。文件包中主要含有 css、html、js、文档、图片、视频等内容:
由于文件中包含有用于呈现文档内容的 HTML,开发者甚至可以将文档托管到网站上。下面以 Apache 为例,讲解将文档托管到网站上所需的步骤:
- 将 .doccarchive 文件拷贝到服务器用于提供文件的目录。
- 在服务器上添加一条规则将以
/documentation或/tutorials开头的 URL 路由到 index.html。 - 再添加一条规则以支持访问文件中的 CSS 和图片等资源。
为了定位到文档,参考文档和文章的 URL 需要以 /documentation 开头,教程的 URL 需要以 /tutorials 开头。举例来说,如果需要定位到 SlothCreator 文档中一个名为 SlothGenerator 的协议,URL 如下:
https://www.example.com/documentation/SlothCreator/SlothGenerator
以下是 .htaccess 文件中配置的内容:
# Enable custom routing.
RewriteEngine On
# Route documentation and tutorial pages.
RewriteRule ^(documentation|tutorials)\/.*$ SlothCreator.doccarchive/index.html [L]
# Route files within the documentation archive.
RewriteRule ^(css|js|data|images|downloads|favicon\.ico|favicon\.svg|img|theme-settings\.json|videos)\/.*$ SlothCreator.doccarchive/$0 [L]
苹果承诺将在今年内开源 DocC,同时发布一个可以托管非官方文档的应用程序,届时即使不用 Xcode 也可以享用 DocC 的文档工作流程,以上复杂的配置过程也将得到简化。
后记
「Talk is cheap, show me the code」的时代已经过去,一份生动的文档不仅能为开源框架锦上添花,同样也是降低沟通成本和普及新技术的利器。随着互联网公司的体量越来越大,技术文档浩如烟海,管理起来如海底捞针,不禁成为团队协作的一大障碍。DocC 是苹果提供的新方案,在可预见的未来,无论是科技公司、开源社区还是 IT 教育机构,都将着手通过这一技术优化自己的文档管理方式,为程序员间的技术交流搭建更高效的基础设施。
关注我们
我们是「老司机技术周报」,一个持续追求精品 iOS 内容的技术公众号。欢迎关注。
关注有礼,关注【老司机技术周报】,回复「2021」,领取 2017/2018/2019/2020 内参
支持作者
在这里给大家推荐一下 《WWDC21 内参》 这个专栏,一共有 102 篇关于 WWDC21 的内容,本文的内容也来源于此。如果对其余内容感兴趣,欢迎戳链接阅读更多 ~
WWDC 内参 系列是由老司机牵头组织的精品原创内容系列。 已经做了几年了,口碑一直不错。 主要是针对每年的 WWDC 的内容,做一次精选,并号召一群一线互联网的 iOS 开发者,结合自己的实际开发经验、苹果文档和视频内容做二次创作。