使用Xcode HeaderDoc和Doxygen文档化你的Objective-C和Swift代码

在一个应用的整个开发过程中涉及到了无数的步骤。其中一些是应用的说明,图片的创作,应用的实现,和实现过后的测试阶段。写代码可能组成了这个过程的绝大部分,因为正是它给了应用生命,但是这样还不够,与它同等重要的还有代码的注释和文档编写。不管代码写的有多好,如果缺少了对应的好的注释文档,很有可能在将来带来麻烦。不幸的是,许多开发者都忽视或忽略了代码文档的重要性,而这非常糟糕,因为好的程序不仅仅是好的代码。它需要更多的东西。

谈到编写注释文档,显然我不是说仅仅简单的在实现文档里添加几行注释。肯定是更多的东西。但是首先,为什么对代码进行注释这么重要?好吧,这里有两个情景:不管你是单独工作,或者你是团队的一份子。让我们来分别解释一下。

如果你是一个正在开发的应用的唯一开发者,有理由相信写注释文档会消耗时间,所以忽略不做会让你更迅速完成目标。除此之外,很容易说服自己既然都是独立开发者了没有太大必要来做注释文档。但是相信我,这将会是在应用开发期间做的最坏的决定。假设你成功的开发完成了应用,无论是在app store上销售或者卖给你的客户,然后你把它保存起来。六个月后,你必须要通过添加几个新功能来创建一个这个应用的新版本。当你重新打开这个工程然后查看已有的代码,在你写下第一行新代码之前一段时间,你会意识到一个残酷的真相:你几乎不记得任何东西!你做过什么,你怎么做的,为什么要这么做,都会很难回想起来!你必须通过一个痛苦的方法来在脑袋里重新唤起这个工程,这个方法就是从工程的最开始,一行行的“解密”你的实现代码。仅仅是几行注释根本没什么帮助,最终直到你理解所有东西之前会用很长的时间且花掉许多精力。正在读这些内容的很大一部分的你们都可能遇到过那种情况,而且我很肯定的给你说过去我也遇到过。这种情况真的是噩梦一样,那时你经常想干脆从头开始做一个工程算了。当然,这里提到的场景可能仅仅会是一个...场景,只要我们花一点点时间来编写合适的注释文档。

另一方面,如果你是团队里的一员来开发工程,那么避开给代码写注释文档将会是灾难性的。当你给其他开发者分享代码时,你必须解释你的观点(在代码里),当时做了什么,是怎样做的,当然其他的开发者也被要求做同样的事情。没有一个情形是大项目的开发者们对后面开发者们开发的代码都有全面的了解,因为若是这样,将会浪费掉很多不必要的时间。因此,在这种情况下的编写注释代码一方面就像是做交流,另一方面也是帮助团队里的其它开发者了解你的代码的含义。毕竟,每个程序员编写代码的风格都跟其他人不一样,所以表达清楚你的代码功能是件必须做的任务。

希望我把观点表达清楚了,现在让我继续说说对于所有编程语言和所有平台都适用的合适的注释文档。不管你是对iOS,web或者桌面系统编写应用:重点就是你在编写代码时就写文档,这样对你(和对其他人)做代码修订时会更简单以及不会花费太多精力。

正如你了解的,在这个教程里我将会重点突出代码注释文档当中最重要的方面。我将会对Objective-C 和 Swift做讲解,因为这两个语言都有许多开发者利用来写应用,当然我也打算向你展示这两个语言的相似和不同之处。更进一步,我会展示怎样为你的应用创建完整的,web-based文档,但是恐怕我必须说这仍然只是仅仅针对 Objective-C的一个选项。

作为一名使用Xcode ID的iOS开发者,你可能曾经想过对于两种语言的注释文档选项应该是相同的。事实并不是这样,同Objective-C 比Swift支持很少的注释文档选项,至少在我写这个文章的时候是这样。但是,它们都给你了充足的“补给”以便你可以写出优秀的注释文档。我们会从Objective-C开始,因为它有很多不止是满足需要的东西要讲解,然后我们将会讲解Swift代码注释文档来结束这个教程。现在没有必要讲述细节的东西,因为我们将会在接下来的部分中看到。

在开始之前,让我提示最后的两件事情。第一,我不是试图让你偏执的写文档,而是说服你编写合适的注释将会提高你的编程生涯。第二,编写代码注释文档是你必须接受的习惯,而绝对不是浪费时间。

Objective-C创建一个demo app

我们从创建一个使用Objective-C的新工程开始,这工程也是我们将会用来对接下来要看到的东西做测试的。如果你还没做,打开Xcode然后创建一个新的工程。因为我们不会做一个真的demo应用,选中Single View Application 就可以了。

在下一步中,命名工程为DocDemoObjC,在Language下拉菜单中确保选中Objective-C 选项。

t28_2_new_project_ObjC_2.png

通过在硬盘上选择一个保存工程的目录地址来结束这个指南。

文档化细节

正如你知道的,在Objective-C 和 Swift中写一条注释的最简单办法是用两条斜杠,如下图展示这样:

1
// This is a comment.

你可以(且必须)像上面那样来放置你的注释,以便分清每个部分。但是,当谈到代码注释文档,我肯定不是指的上面的注释。如果整个教程都专注于此肯定毫无意义。注释文档意味着以结构化的方法使用特殊的关键字,也叫标签来写注释,使用特殊的符号来标示注释区域,因此编译器可以完美的理解这个过程。只有一些简单的规则需要遵守。上面操作的所有结果就是你的注释文档可以在三个不同的地方展示:

  1. 在Utilities面板的Quick Help Inspector 里。

  2. 当你按下Option键然后点击方法,类或属性名时弹出的帮助菜单 Help Popup 里。

  3. 在代码实现弹出框里。

除此之外,合适的代码注释让你可以使用众多的工具来为你的应用创建完整的HTML文档,例如the HeaderDoc 和 Doxygen。它们两个稍后会提到,而且你会看到我刚才所说的是怎样实现的。

记住上面所说的,是时候更近一步了。当使用Objective-C写代码时有三种可能的方法来标示一个注释文档区域:

  1. 把你的注释包含在/** – */ 块里。

  2. 把你的注释包含在 /*! – */块里。

  3. 以三条斜杠 ///开始的注释行

在这个教程实例中我们将会用第二种方法来写我们的注释文档。我选择它出于两个原因:第一,它是唯一一个能被HeaderDoc识别的格式,而且如果注释块不是以它开头,帮助页也不会被生成。第二,尽管Doxygen更倾向于第一种格式,它也能识别第二种。因此,第二种格式将会在两种方法下都适用。第三种格式通常在注释一行时用到,例如属性值时,因此、,我们还是坚持用第二种格式。

现在,当写注释文档时,你可以使用特定的关键值(或标签)。标签被分为两个大类:第一个是 top level 标签,它可以用来指定哪种类型的代码被注释了,例如类,结构体,文件,等等。注意top level标签不是必须使用,但是肯定会帮助导出工具(例如 HeaderDoc 和 Doxygen)创建出更好的结果。第二个是second level标签,它指定了每个注释文档块的细节。这个类型的标签正是你需要的,因为每一个都定义了另外的注释文档部分。

下面我给出了最重要的second level标签,但是注意了这并不是全部。我们稍后会看到一些 top level标签。我这里列出来的是最常用到的:

  • @brief: 使用它来写一段你正在文档化的method, property, class, file, struct, 或enum的短描述信息。

  • @discussion: 用它来写一段详尽的描述。如果需要你可以添加换行。

  • @param: 通过它你可以描述一个 method 或 function的参数信息。你可以使用多个这种标签。

  • @return: 用它来制定一个 method 或 function的返回值。

  • @see: 用它来指明其他相关的 method 或 function。你可以使用多个这种标签。

  • @sa: 同前一条类似。

  • @code: 使用这个标签,你可以在文档当中嵌入代码段。当在Help Inspector当中查看文档时,代码通过在一个特别的盒子中用一种不同的字体来展示。始终记住在写的代码结尾处使用@endcode标签。

  • @remark:在写文档时,用它来强调任何关于代码的特殊之处。

你可以在 这里 (HeaderDoc User Guide)找到包含所有支持的标签的列表。

注意@符号是每个标签的前缀。同样,你也可以在文本中使用特殊字符switches,这样就可以改变它的类型和格式。例如,Text 以会让 Text单词成为黑体,同时Text也会让 Text 单词的类型为italic. 有趣的是你也可以把部分文本以代码形式展现(不是代码段),如果写下@cText,当帮助文档在Xcode上展现时,它会导致展示一个不同的字体格式。

除开上面说的,你也可以替换@符号为反斜杠(\)。那样的话标签就会像这样被展示: \brief, \param, \return,等等。注意反斜杠最常在Doxyten 文档系统里面被使用,而@符号常在HeaderDoc里面被使用。在这里我们会在所有地方使用@,因为它在两个系统中都通用。

Objective-C代码文档化

让我们看看以上我提到的内容是怎样使用的。打开ViewController.m文件,在类的私有部分中添加下面的属性:

1
2
3
4
5
@interface ViewController ()
  
@property (nonatomic, strong) NSString *myName;
  
@end

然后如下面所示添加注释文档:

1
2
/*! @brief This property knows my name. */
@property (nonatomic, strong) NSString *myName;

然后到viewDidLoad方法中,开始输入这个属性。你将看到在代码填充弹出框里我们刚刚写下的注释就在那里!

 

01.png

而且不仅这样。当在键盘上按住Option 键,点击myName属性就会让帮助窗口弹出:

02.png

更多的,如果在Utilities面板打开 Help Inspector,你会在那里也找到相同的文档。

03.png

注意在上面的注释当中@brief  标签可以被去掉而不会导致任何问题。意味着下面的这条注释也是有效的:

1
2
/*! This property knows my name. */
@property (nonatomic, strong) NSString *myName;

同样的,下面的也一样:

1
2
/** This property knows my name. */
@property (nonatomic, strong) NSString *myName;

而且下面的这条也一样:

1
2
/// This property knows my name. */
@property (nonatomic, strong) NSString *myName;

让我们来看看第一个怎样展示文档方法的简单示例。此时你必须了解如果你的目标是创建一个HTML文档,那么只是公有方法(在头文件里的)的文档是可见的。无论你在类的私有部分中写的任何文档在Xcode帮助文档里都是可见的,但是任何实现部分都没有被导出到注释文档里。所以,记住这些,现在让我们在ViewController.h 文件里定义一个公有方法:

1
2
3
4
5
@interface ViewController : UIViewController
  
-(float)toCelcius:(float)fromFahrenheit;
  
@end

很显然,这个方法将会把华氏度转换为摄氏度。现在我们来添加注释文档:

1
2
3
4
5
6
7
8
9
10
11
12
/*!
    @brief It converts temperature degrees from Fahrenheit to Celsius scale.
  
    @discussion This method accepts a float value representing the temperature in Fahrenheit scale and it converts it to the Celsius scale.
  
                To use it, simply call @c[self toCelsius: 50];
  
    @param  fromFahrenheit The input value representing the degrees in the Fahrenheit scale.
  
    @return float The degrees in the Celsius scale.
 */
-(float)toCelcius:(float)fromFahrenheit;

注意在上面我们使用HTML开关来让所有包含的文字分别是粗体和斜体。同样注意我们是怎样使用@c开关来标识内嵌代码

为了在Xcode帮助当中查看这个注释文档是怎样展示的,先打开 ViewController.m 文件然后定义这个方法如下:

1
2
3
-(float)toCelcius:(float)fromFahrenheit{
    return (fromFahrenheit - 32) / 1.8;
}

然后把光标放到方法名上,在Quick Help Inspector里查看:

03.png

可以看到Xcode把文档里的每个部分都格式化的展示出来。在help 弹出窗口里也一样(option键+点击方法名):

04.png

如果在viewDidLoad 方法中调用这个函数,那么就可以在函数自动填充窗口里看到简介描述:

05.png

很棒,是不是?可以想象你的代码那样文档化后会变得多有帮助且能自我解释清楚代码意义,特别是当你同其他团队人员一起工作时。

为了让这个例子更加有趣,我们添加另一个公有方法正好可以做相反的事情:把摄氏度转换为华氏度。打开ViewController.h文件,然后添加下面的方法声明,以及它的文档注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*!
    @brief It converts temperature degrees from Celsius to Fahrenheit scale.
  
    @param  fromCelcius The celsius degrees value.
  
    @return float The degrees in the Fahrenheit scale.
  
    @code
        float f = [self toCelsius:80];
    @endcode
  
    @remark This is a super-easy method.
 */
-(float)toFahrenheit:(float)fromCelcius;

在上面段落里我们添加了两个新的标签:一对 @code – @endcode标签和@remark 标签。你将会马上看到它们是怎样展示的。

我们到 ViewController.m文件里去实现这个方法:

1
2
3
-(float)toFahrenheit:(float)fromCelcius{
    return fromCelcius * 1.8 + 32;
}

现在我们看看Help弹出框如下:

06.png

非常漂亮!现在你自己的文档跟Xcode默认文档比起来毫不逊色。

在进入下一部分前,打开ViewController.h文件,然后添加下面的属性声明(当然也包括注释):

1
2
/*! An application delegate object. */
@property (nonatomic, strong) AppDelegate *appDelegate;

同它一起,导入AppDelegate类:

1
#import

添加上面属性到类里面的原因就是稍后可以让我们看到属性值和我们已经创建好的方法是怎样用文档工具(HeaderDoc 和 Doxygen)被导出的。

文件、类、结构以及枚举

在前面部分我们浏览了写属性或方法时需要遵守的记录文档规则。我故意从属性和方法开始介绍编写文档,因为你的大部分开发时间都是消耗在那里。现在我们已经看到了最主要的部分,现在继续看看怎样对 files, classes, structs 和 enums 添加注释。

让我们从files开始,怎样在Objective-C中写下能提供信息的文档。当同其他人分享编程工作时,或者当你以开放源代码组件形式分发代码时,那么添加file  documentation就是必须的,因为这是最佳的地方来向你的开发伙伴或者使用你代码的人提供明确的信息。通常,你将要更关注header 文件(.h)以及在它里面的描述信息,因为这些会保留在将被导出的最终文档里(并不在Xcode里);但是,这并不代表你不需要在implementation文件中添加描述信息。不要忘记当在Xcode中打开工程时,所有的东西都在那儿,不仅仅是header 文件,因此保证你不会留下没被记录文档的部分。除此之外,实现部分不会在导出文档中看到,但是所有文件的描述信息始终都是可见的。

让我介绍一些当你在记录一个文件时会用到的新标签:

  • @file: 使用这个标签来指出你正在记录一个文件(header 文件或不是)。如果你将使用Doxygen来输出文档,那么你最好在这个标签后面紧接着写上文件名字。它是一个top level 标签。

  • @header: 跟上面的类似,但是是在 HeaderDoc中使用。当你不使用 Doxygen时,不要使用上面的标签。

  • @author:用它来写下这个文件的创建者信息

  • @copyright: 添加版权信息

  • @version: 用它来写下这个文件的当前版本。如果在工程生命周期中版本信息有影响时这会很重要。

当然你还可以使用更多的标签,但是这些都是最常使用的一部分。我建议你通览HeaderDoc 或 the Doxygen文档,这样就可以发现一些额外的你想使用的关键字。

现在我们来看对ViewController.h 头文件添加注释。找到文件的开头,就在import 命令之前。在那里添加下面的几行:

1
2
3
4
5
6
7
8
9
10
11
/*!
@header ViewController.h
  
@brief This is the header file where my super-code is contained.
  
This file contains the most importnant method and properties decalaration. It's parted by two methods in total, which can be used to perform temperature conversions.
  
@author Your_Name
@copyright  2015 Your_Name
@version    15.12.7
*/

你可以把Your_Name 替换成你自己的名字或者公司的名字。同样的,使用 brief标签而不是省略它是很好的习惯,因为它会让文档系统(在HeaderDoc 和 Doxygen中稍后将会看到)在输出的HTML网页上展示你在这儿添加的简短描述。我再提醒一次,在Doxygen里你可以使用反斜杠来代替“@”。同样的,在这里你将不会看到刚才说的文档长什么样,但是我们将会在后续输出HTML文件时展示。

以上的都很棒,但是实事却是在大多数情况下,你创建的新文件里由Xcode自动添加的提供信息的默认注释都非常好而且够用了。当你在团队里同其他人一起协作,并且每个成员必须描述清楚他负责的那些文件的细节信息时,或者当你打算使用 HeaderDoc 或 Doxygen来输出一个工程的完整文档时,又或者当你是独立开发者但是工程拥有数量众多的文件时,你可能想创建一个文件描述块。不管怎样,由你自己决定你的文档系统需要完善到哪个level。

让我们来看看怎样对class或者protocol写注释文档。再一次的,我只给出最常用的标签。自己查看说明文档了解更多标签信息。

  • @class: 用它来指定一个class的注释文档块的开头。它是一个top level标签,在它后面应该给出class名字。

  • @interface: 同上

  • @protocol: 同上两个一样,只是针对protocols

  • @superclass: 当前class的superclass

  • @classdesign: 用这个标签来指出你为当前class使用的任何特殊设计模式(例如,你可以提到这个class是不是单例模式或者类似其它的模式)。

  • @coclass: 与当前class合作的另外一个class的名字。

  • @helps: 当前class帮助的class的名字。

  • @helper: 帮助当前class的class名字。

实际上,可能除了superclass你几乎很少用到上面的标签。可用标签的列表很长,只是我觉得在这里列出更多没太大意义。必须指出的是从superclass开始以及下面的所有标签,都不能被 Doxygen,识别,只能被HeaderDoc识别。同样的,在Xcode里的Quick Help和Help Popup弹出框里展示的是各个标签旁边的值,而不会展示标签本身。因此,用不用他们取决于你是否使用文档系统以及使用哪一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
/*!
@class ViewController
  
@brief The ViewController class
  
@discussion    This class was designed and implemented to help people covert temperatures between the Fahrenheit and Celsius scales.
  
@superclass SuperClass: UIViewController\n
@classdesign    No special design is applied here.
@coclass    AppDelegate
@helps It helps no other classes.
@helper    No helper exists for this class.
*/

现在,如果把光标移动到ViewController 类的名字时,或者按住option键然后点击它,就可以在Xcode帮助窗口中展示了上面的描述。

07.png

可以看到标签都没有展示出来,但是在这种情况下并没任何影响。

很棒的是这样能使你在声明这个类的对象时可以看到类的简介。眼见为实,打开ViewController.m文件然后定位到viewDidLoad方法。在那里,声明一个本地ViewController对象。你将会在代码补充窗口里看到类的简介。

08.png

按照上面的方法也可以对protocol添加注释。在ViewController.h 文件开头添加下面的几行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*!
    @protocol ViewControllerDelegate
  
    @brief The ViewControllerDelegate protocol
  
    It's a protocol used as a demo here. In a real application it would be quite useful.
*/
@protocol ViewControllerDelegate
  
/*!
    Nothing to say here... Just testing documentation.
*/
-(void)thisIsADelegateMethod;
  
@end

Option键+点击protocol的名字就会看到注释在Help 弹出框里展示出来。

09.png

可以看到在上面,我们也声明了一个delegate 方法。可能此刻你觉得那毫无意义,但是我故意把它放在这里是作为示例demo;当我们使用HeaderDoc和Doxygen来导出文档时就会在导出的页面看到它了。

现在我们讨论了files,classes 和protocols 希望你有了一个大概的了解,现在看看一些特殊示例:怎样对structs 和 enumerations进行注释。它们的共同点是在两个当中都使用 @typedef top level  标签,以此来标示注释块的开始(再次提醒使用top level 完全自愿)。

特别是对于Doxygen系统,不使用@typedef标签,你应该对structs使用@struct 标签,对enums使用@enum标签。

让我们看以下的代码。把它添加到ViewController.h 文件的interface之前:

1
2
3
4
5
6
typedef struct {
    int sun;
    int clouds;
    int rain;
    int snow;
} WeatherConditionsInDays;

现在把下面的注释添加在它前面:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*!
@typedef WeatherConditionsInDays
  
@brief  A struct about the weather.
  
@discussion
The values of this structure represent how many sunny, cloudy, rainy, and snowy days existed over the last year. If this was a real app, they could be perfectly used.
  
@field sun Good weather
@field clouds  Where's the sun?
@field rain    Get an umbrella
@field snow    Watch out... A snowball is coming!
*/

可以看到,出现了一个名叫@field的新标签。这个标签的目的是对struct里面的每一个变量进行描述。再次,我必须强调HeaderDoc和Doxygen的不同之处。在HeaderDoc里,这个标签是可接受且有效的。但是,在Doxygen里却不是这样。在这个案例里我们做的仅仅是分开对每一个变量进行注释。这样做会使当我们在implementation文件里使用它们时能展示出每个的注释。我们来看看吧(注意标签和变量上方的注释有着不同的值,所以在后面会更轻松的区别出来):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*!
@typedef WeatherConditionsInDays
  
@brief  A struct about the weather.
  
@discussion
The values of this structure represent how many sunny, cloudy, rainy, and snowy days existed over the last year. If this was a real app, they could be perfectly used.
  
@field sun Good weather
@field clouds  Where's the sun?
@field rain    Get an umbrella
@field snow    Watch out... A snowball is coming!
*/
typedef struct {
    /*! Good weather */
    int sun;
    /*! At least it's not raining */
    int clouds;
    /*! Don't forget to get your umbrella */
    int rain;
    /*! Time to go skiiiiiing */
    int snow;
} WeatherConditionsInDays;

如果现在到 ViewController.m 文件中定义一个这个struct的变量,无论输入以上任何变量的一个都会在弹出窗口里看到它的描述。

Enumerations也是同样的,所以我把它作为练习留给你自己去创建一个enum类型然后进行注释。非常简单,是不是?当enum创建好后,到viewDidLoad方法里去查看它的注释会不会在Xcode的帮助选项里展示出来。

查看错误

在先前的例子里可以看到,在@param 标签旁必须写出变量名字,之后才是描述信息。当然,误输入一个变量名,特别是当它有些复杂时,以及创建的文档包含错误都是很有可能的。但是,有个方法可以避免这种情况发生,我猜你可能并不知道Xcode可以在这时成为你的可靠助手。

尽管Xcode在文档开始写时就处理了,它也可以帮助你避免误输入任何变量名。只要开启一个配置就能让它做到这点。让我们来看看我到底想表达的是什么:

在 Project Navigator里,点击工程,找到Build Settings标签,如下图所示:

11.png

这样做后,在搜索框里输入comments关键字然后等待下方给出的结果。其中一个结果就是名为Documentation Comments的配置,通常它的默认值是NO。你做的仅仅是把它的值设为YES,一切就绪。

12.png

现在,我们来看上面的配置是怎么样影响我们为代码写注释的。打开ViewController.m 文件,然后到私有类中,在那里我们将声明一个私有方法。如下:

1
2
3
4
5
@interface ViewController ()
  
-(float)showCurrentTemperatureInCity:(NSString *)targetCityName showInScale:(NSString *)preferredScale;
  
@end

正如我们将要实现这个方法,它会返回所选择的城市天气值,单位就是先前提到的(华氏度或摄氏度)。现在,我们在它之前添加下面的注释:

1
2
3
4
5
6
7
8
9
/*!
    This method returns the current temperature in the selected city, expressed in either Fahrenheit or Celsious degrees.
  
    @param  targetcityName  The city that the temperature will be returned for.
    @param  preferredScale  Fahrenheit or Celsius.
  
    @return float   The current temperature of the city.
*/
-(float)showCurrentTemperatureInCity:(NSString *)targetCityName showInScale:(NSString *)preferredScale;

当你把上面的注释copy-paste到Xcode里,一个警告就会在第一个变量被注释时弹出,告诉我们变量名targetcityName在方法声明里找不到。猜猜怎样?这是对的!我没有输入正确的变量名(targetCityName),而是输入了错误的变量名(targetcityName)因为没有大写“city”的第一个字母。这是在大型工程拥有许多注释时,我们可能会忽视的地方,但是幸好Xcode给了我们“另一双眼”来帮助。

现在,如果你点击警告栏左边的三角icon,就会看到Xcode自动推荐了正确的变量名,只要点击它就能修复。或者,自己修复它。

12.png

有了上面的这些,再也不需要担心在写文档时误输入任何变量名了。

Producing Documentation With HeaderDoc(使用HeaderDoc生成文档)

现在关于代码注释我们已经涵盖了主要内容,现在进入另一个部分,让我们看看怎样创建包含往工程里添加的注释的HTML文件。在这个部分,我们将使用HeaderDoc,一个与写入文件里的文档配合很棒的好工具。我推荐你访问 这个网站 来了解更多信息。我们将使用HeaderDoc来输出工程的所有注释部分到HTML页面里。小工程这样做可能没太大意义,但是对于大型工程或你将为其他人提供自己的SDK时,一个对应的文档会很有必要。HeaderDoc工具实际上是一个 command-line工具。它提供详细的不同的分支来配置导出步骤,你可以在上面我提供的链接里找到。这里,我们将使用一个分支,那就是很有用的可以指定输出目录(保存被导出文档的目录)的分支。

我们来看怎么做。首先,为即将被生成的文档创建一个目录。为了便于访问,我在桌面建一个目录,当然你也可以选择任何你喜欢的目录,只要你更新稍后会看到的path路径。我在桌面上创建了一个DocDemo目录,并在此添加了两个子目录:一个是HeaderDoc,一个是Doxygen。每个工具生成的文档会让在各自对应的文件夹中。

13.png

接下来,你必须打开Terminal,可以点击LaunchPad > Other group > Terminal,来打开或者在Spotlight下输入 terminal来打开。

14.png

现在,用terminal去定位到你的工程所在的目录,使用下面几个简单步骤就可以达到目的:

  1. 在Terminal里写下cd  指令然后输入空格键。不要按下回车。

  2. 在Finder里,定位到包含工程的根目录。

  3. 拖拉这个目录到terminal下,如下图所示。

15.png

然后点击回车键,为了确保你在正确的目录下可以使用pwd 指令(始终在terminal中)

在这里我们要使用的HeaderDo指令叫做headerdoc2html,指令格式如下:

1
headerdoc2html -o OutputDirectory InputDirectory

OutputDirectory目录是我们先前创建的目录,而input目录是工程文件存在的目录。

现在,让我们实际使用它。在terminal窗口,写下或者复制粘贴下面的指令:

1
headerdoc2html -o

注意:在-o后面有一个空格符号。

接下来,到Finder中找到将会存储导出文档的目录。按照上面描述的步骤,拖拉目录到terminal。之后,输入input目录地址且在后面加一个/符号。全部指令将会看起来像下面这样:

1
headerdoc2html -o /Users/gabriel/Desktop/DocDemo/HeaderDoc DocDemoObjC/

 

16.png

你将会看到很多东西展示出来,当前不需要特别留意。当它完成后,标记和复制下来output目录地址,在terminal中输入下面的指令:

1
gatherheaderdoc

然后粘贴复制的路径。按下回车键然后让它运行。这个指令会创建一个内容页的表格,这样所有的注释文件,类和方法都会展示在一个地方。

好了。现在定位到Finder,然后在浏览器中打开masterTOC.html文件。下面是你将会看到的东西:

17.png

如果你点击ViewController链接,下面是你将会被引导进入的页面:

18.png

 

在这里你会看到文件的描述信息,class,protocol和 struct以及指向它们的链接和简短描述。在相同页面上也会展示struct的详细信息。

19.png

注意有一部分含有重复的值,那是因为我们又使用了@field标签又在每一个struct变量的上方使用。如果你想,也可以重回到Xcode然后删除掉其中的任何一个。接下来,在terminal中重新运行HeaderDoc指令然后回到这里。

如果你点击一个class链接,会跳转到一个新的页面,这里你可以看到它的描述信息,在header文件中声明的两个methods和一个property。

20.png

现在,你已经看到了结果了,随便浏览文档中的任何部分然后看看所有东西都是怎样展现的。HeaderDoc的用处远远不止这些,但是这却是在大多数情况下你需要的东西。

使用Doxygen生成文档

现在让我们抛开HeaderDoc然后来看看且使用一个广泛流传的注释系统,叫做Doxygen。在查看它的细节之前,我想说Doxygen并不是一开始就是为了在Objective-C中生成注释文档而设计的。但是,它却在针对C 和C++语言时可以完美的完成工作,你将会亲眼目睹,它其实支持很多的语言。除开这些,它还包含非常多的注释标签,如果你决定了使用Doxygen工具来生成注释文档,那么你可以使用任何标签来拥有更棒的兼容性。

Doxygen是一个第三方应用想要使用它之前必须下载。对所有的操作系统它都要对应版本,所以当你并不是只为iOS开发时也都可以使用。此刻,我将给你三条很重要的链接:

  1. 这个链接 里你可以找到关于代码注释的所有资源。

  2. 这里 你可以找到Doxygen支持的所有标签,点击每一个标签将会得到它的用途描述信息。

  3. 最后,你可以访问 这也页面 来下载应用。

在下载前,让我提醒你可以在Doxygen的网站上找到比我先前提到的内容多得多的东西。实际上,正如下面的截图所示,在左侧有一个菜单面板,你可以使用它来找到的Doxygen各个部分的内容和数不尽的细节以及how-tos.

21.png

现在,访问我刚才在上面给你的链接地址,然后滑到页面的下方直到找到一个名叫A binary distribution for Mac OS X 10.5 and later的区域。点击 ftp或http链接来初始化包下载过程。依据你的网络速度,下载过程可能会需要几秒钟来完成,文件大小大概为55Mb。

下载完成后,打开包。然后找到Doxygen应用然后把它拖到你的Applications目录下。

如果你不想把它添加到Applications目录下也没问题。可以把它拖到任何你想放的位置。比较,Doxygen是一个完全self-contained的应用,无论你把它放在哪里,移除它只需要删除它的APP文件。

假设现在你已经把它复制到了目录下,点击Lauchpad来轻松找到它。点击它运行。

注意:如果得到一个提示信息说一个应用程序不能被打开是因为它来自没有被认证的开发者,按照下面的步骤来跳过它:在Finder里,打开Applications目录。定位到Doxygen应用,然后按下Ctrl键+点击它。在菜单中选择Open 选项,然后在新的视图框中点击Open 按钮。

现在把Doxygen应用放一边,回到Xcode。我们将会在两个标签中做些改变,这样所有东西都会被识别。确保打开ViewController.h文件,然后在描述块里替换@header  top level标签为@file标签。还有,注释中的struct块也需要一些改变, @typedef 标签都必须被@struct标签替代。当这一切都做好后,又一次离开Xcode。

如果以前用过Doxygen,你肯定知道应该怎么做。但是,这里我假设你是第一次使用这个应用,所以让我向你展示一些最重要的步骤。

下面是Doxygen第一次运行时的初始窗口:

22.png

在我告诉你正确的需要使用的设置信息前,有必要说明Doxygen提供两个使用模式:Wizard模式由一个简单且通用的方法组成,以及Expert模式,在这里很多的配置信息都可以被指定这样你可以定制化每一个输出文档的细节部分。

我不会把重点放在Expert模式上,因为要应用的配置条件高度依赖于每位开发者的个人需求。意味着我们将专注于Wizard模式,但是在此之前,我想还是有必要快速了解一下Expert模式。在主视图区域里点击 Expert按钮,马上就会在主面板上看到给了你很多的配置信息。你可以上下滑动查看所有的配置,但是远不止于此。在左边,有一个小面板标题为Topics,点击其他的topic就可以获取它自己的配置。如果有时间,浏览它们所有。你将会找到想在你的应用当中使用的有用的选项。

现在,我们把焦点放在Wizard模式。确保点击到了正确的按钮,这样就可以跟上我将要描述的内容。首先,在视图顶部我们必须指定Doxygen 从哪里运行。点击Select按钮,然后在电脑里选择Application目录,或者任何其他你把Doxygen应用拷贝进去的那个目录。

接下来,我们来指定工程名字。在Project Name输入框里,输入 DocDemo in Objective-C值(或者任何你想用的值)。如果你愿意,也可以把下面的输入框值都填上。在那之下,我们必须指定指向工程的路径。再一次,使用Select按钮且定位到工程的根目录中。选中Scan recursively会很不错,因为Doxygen就也可以扫描所有子目录了。

最后,指定存储生成的文档的地方。如果你还记得的话,我们已经为此在桌面的 DocDemo 目录下新建了子目录Doxygen 。因此,点击Destination Directory旁边的Select按钮,然后选中它。

23.png

接下来,在左边的Topics列表里,选择Mode选项。在新的配置里,选中All Entities 选项:

24.png

接下来,还是在Topics列表里,选择Output选项。在这里你可以找到很多的导出选项。自由选择任何你想要的output种类。在这个例子里,我屏蔽了 LaTeX选项,只让HTML有效。

25.png

最后,在Diagrams选项里你可以保留默认设置。

现在是时候输出文档了。请确认在继续之前一定要把先前的配置信息全部设置好。设置好了?很好,我们继续吧。点击Run按钮(在Wizard和Expert 按钮旁边),然后现在在主视图区域你可以看到一个名叫Run doxygen的新按钮。点击它让应用帮你启动创建HTML文件。在白色区域你将会看到一些output信息,如果事情出差错了,你也会在这里看到。

不管怎样,只要它完成了,打开Finder然后定位到输出目录去查看导出文件。你会看到有一系列的文件被创建了,而你需要找到的就是 index.html文件。双击在浏览器中打开它。其实如果你不是那么在意非要看到导出的文件,可以简单在Doxygen视图里点击Show HTML output 。

这是在打开index页面时看到的第一个屏幕。

26.png

它只是包含了我们先前设置的工程名,创建时间,和在顶部的许多链接。使用这些链接去浏览一下相应内容。例如,如果点击Classes链接,你就会得到一个包含了工程中的所有classes的列表。有趣的部分是在每个class旁边都展示了它的简短描述信息(仅仅是那些我们写了的)。

27.png

下面是当你点击 ViewController class时会看到的内容:

28.png

可以看到,工程中的方法和一个公有属性的详细文档可以在这里找到。另外一个有趣的地方是在Files菜单下面,在这里所有的被分析的文件都被列举出来,选中ViewController.h文件。在哪里你可以找到文件的描述信息,以及我们声明的所有东西:calss, protocol, 和struct。

29.png

使用More…链接来查看上面的所有内容的详细信息。还有一个链接名字为“Go to the source code of this file.”如果点击它,将会展现ViewController.h头文件里的代码。注意不管在头文件里的任何public的内容,都可以在这里展示出来。但是不要指望可以看到任何实现代码。那些是“专属于你”的。

30.png

好了,此刻我相信你已经对所有以上内容有了大概理解。定位到输出的HTML页面,回到Xcode中修改注释文档信息,然后重新导出所有内容。还有,不要犹豫去设置高级配置信息然后查看将会发生什么。大体上,尽量多的体验更多内容,然后更加熟悉Doxygen。无论是小工程还是大工程,它都是一个很棒的工具。

用Swift创建一个Demo App

让我们再次翻开新的篇章,说说关于用Swift写的代码的文档记录。为了让事情尽可能的清晰,我们创建一个新的工程,这次使用Swift。

因此,在Xcode中建一个之前,在第一步中指明应用的模板为 Single View Application。接下来,命名工程为DocDemoSwift,确保选中的语言是Swift。接着,选一个路径来保存工程,让Xcode创建好工程。

Swift代码文档化

用Swfit的代码注释文档跟用Objective-C的比,没那么强大,我把为什么这样的讨论放在最后。不幸的是,HeaderDoc和Doxygen都不支持Swift(至少现在是这样,不能说将来会怎么发展),现在的文档格式是基于reStructuredText,它是一个开源工程并且可以在这里找到更多信息。

这个教程里先前看到的所有标签,只有两个可以在这个示例里使用:param和return, 通常使用的是(注意这个在末尾的“s”)。还有,@或者反斜杠 \ 都不支持。取而代之的是,这两个标签都被包含在了冒号里,例如:param:。在这之后,变量名必须要写,随后写上描述信息。

brief和discussion标签没有被使用,但是相关的地方可以如标签意义描述那样添加文档,意味着在文档最开头的简短文字会被当做简介,而随后的更大块的文字内容会被认为是描述信息。

这里的新的有趣的事情就是在描述部分,你可以添加有序的和无序的列表,连同描述信息一起。例如,添加一个有序列表你只需要写下:

1
2
3
1. First item
2. Second item
3. Third item

对于无序列表,你可以使用星号(*),或者破折号(-)标志。例如:

1
2
3
* An item
* Another item
* More items

和:

1
2
3
- An item
- Another item
- More items

注意:如果你对Markdown 语法很熟悉,那么你已经了解了上面的内容。

为了在讨论区域添加fields,你只需要写下field名字并且被冒号包围,然后写下描述信息:

1
:MyField: This is a field example

以上所有,包括那两个标签(param和returns)对于写出恰当的文档已经足够。尽管不像在 Objective-C 里有那么多的选择,我相信前面的所有内容已经足够,因此我不会再展开。

我们到Xcode中来看看上面所说的示例。打开ViewController.swift文件,然后在里面定义下面的方法(同 Objective-C 例子差不多):

1
2
3
func toCelsius(fromFahrenheit: Float) -> Float {
    return (fromFahrenheit - 32) / 1.8;
}

记住前面所说的对Swift写的代码的注释文档的描述,下面是我们怎样把在Objective-C版本中的相同的注释写下的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
It converts temperature degrees from Fahrenheit to Celsius scale.
  
This method accepts a float value representing the temperature in Fahrenheit scale and it converts it to the Celsius scale.
To use it, simply call toCelsius(50) or self.toCelsius(50)
  
:param: fromFahrenheit The input value representing the degrees in the Fahrenheit scale.
  
:returns:   float The degrees in the Celsius scale.
*/
func toCelsius(fromFahrenheit: Float) -> Float {
    return (fromFahrenheit - 32) / 1.8;
}

注意:在这里我们使用的 /** – */ 标记。在Help弹出框里查看,结果如下:

30.png

同样,如果在viewDidLoad方法里键入方法名字,简短的描述信息会出现在代码填充框里:

31.png

现在,我们创建一个不做任何事情的超级简单的新方法:

1
2
3
func myHelloMethod(){
    println("Hello there")
}

我们将会为这个方法的文档创建列表和fields。你将会看到的只是一个示例,所以不要深究注释里的逻辑关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
    This method was implemented to do nothing hard, just to say hello.
  
    Here is a demo of an ordered list:
  
    1. One
    2. Two
    3. Three
    4. Four
  
    How about an unordered list?
  
    * North
    * East
    * South
    * West
  
    Let's add a couple of fields now:
  
    :Job: My dreaming job
    :Salary:    My dreaming salary
  
*/
func myHelloMethod(){
    println("Hello there")
}

按住Option键然后点击方法名,下面就是将会在Help弹出框里展示的信息:

33.png

上面所有几乎是你需要的所有记录Swift写的代码的文档。但是,在阅读了reStructuredText手册之后,一定要尝试更多的选项(或者其中一些...它非常广泛)。

总结

在这个教程里我们已经看到了关于代码注释的很多方面的内容。我们介绍了 Objective-C和Swift,且都对每一个的最重要的规则都过了一遍。你会发现,在Objective-C 里你可以使用更多的选项,但是,这些工具在针对Swift时也很好用。我今天展示的并不是所有。有很多其它的内容待你发现和利用,我的目的是向你介绍最常用的记录文档方法。在这里你所看到的,是10个情况中9个你都会遇到的。还有,不要忘记了我们介绍的两个有趣的工具,HeaderDoc和Doxygen。它们都可以输出很棒的文档,它们将会成为你友好的“朋友”。最后,我想再次突出强调注释你的代码是非常重要的工作。你可能经常会怀疑这点,但是相信我,在这点上花费的每一秒都是值得的。通过写下合适的注释文档来帮助你自己和其他人,直指核心,解释你的代码中你所做的所有事情。如果你还不习惯这样做的话,最好从现在开始,即便你已经不再是个年轻的开发者。回见!

 

posted @ 2016-09-14 11:37  FakeCoder  阅读(295)  评论(0编辑  收藏  举报