Cocoa code comments and documentation generation
The Documentation specification portion of this article is taken from Nate Cook, author of NSHipster’s Swift Documentation
Contents of this article
background
It used to be thought that good code was self-explanatory and didn’t need comments, but it turned out not to be. Even on personal projects, the importance of code comments is undeniable. After all, a human memory lasts only seven seconds!
A developer who has moved to Cocoa development from another language is 😺 to its long code, which in Objective-C is so long that its code effectively speaks for itself. Like a stringByAppendingPathExtension: explicit type and parameters, this method does not generally give too much imagination. Swift, however, is different.
But even self-explanatory code can be improved with documentation, and with a small amount of effort can yield significant benefits to others.
Document generation tool
Every modern programming language has comments: non-executable natural languages marked by a special sequence of characters, such as //, /**/, # and –. A document annotated in a special format that provides an auxiliary explanation and context of the code that can be extracted and parsed using compilation tools.
Headerdoc has been Apple’s preferred documentation standard since the early 2000s. Starting from Perl scripts that parse reluctant Javadoc comments, Headerdoc eventually became the backend engine for Apple’s online documentation and developer documentation in Xcode.
With the release of WWDC 2014, the developer documentation was overhauled and redesigned to include Swift and Objective-C support.
appledoc
Like Javadoc, AppleDoc can generate HTML and Xcode-compatible.docset documents from.h files.
Doxygen
Mostly used in C++, but generally not well received by the iOS/OS X developer community.
Jazzy
Support objective-C and Swift, hook code AST tree to get exact comments.
Cocoa documentation specification
Like many of Apple’s developer ecosystems, Swift changed everything. In the spirit of “moving with The Times and living with the new,” Xcode 7 replaced Headerdoc with the fan favorite Markdown, especially Swift style Markdown.
The shortcut key for generating the Document template in Xcode is Option (Alt) + CMD + /
Here are the most basic Cocoa comments.
Objective-c style comments:
/// Let's say something
///
/// @param bar I'm paramter
/// @return I'm return value
- (id)fooBar:(NSString *)bar;
Copy the code
Swift style code comments:
///
/// Let's say something
///
/// - Parameter bar: I'm paramter
/// - Returns: I'm return value
func foo(bar: String) -> AnyObject{... }Copy the code
Basic marking rules
Document comments by using /**… */ multi-line comments or ///… A single line comment to distinguish between. The content inside the comment block supports the standard Markdown syntax as follows:
- Paragraphs are separated by blank lines
- Unordered lists can consist of more than one bullet character:
-
,+
,*
,•
- Ordered lists use Arabic numerals
One, two, three...
Followed by a dot1.
Or right parenthesis1)
Or parentheses on both sides(1)
- The title to use
#
Used as a prefix for the content divider---
- Supports links and images, which will download web-based images and display them directly in Xcode
/ * * Hello, documentation
[Tutu Edmond wood] (https://looseyi.github.io/)
# Lists You can apply *italic*.**bold**, or `code` inline styles. --- # Unordered Lists - Lists are great, - but perhaps don't nest; - Sub-list formatting... - . isn't the best. --- ## Ordered Lists 1. Ordered lists, too, 2. for things that are sorted; 3. Arabic numerals 4. are the only kind supported. * /Copy the code
preview
Summary and Description
The beginning of the document’s comments will be called a “Summary”, and the rest will be grouped together into a “Discussion”.
If a document comment begins with anything other than a paragraph, all of it goes into the discussion.
Arguments and return values
Xcode can recognize special fields and separate them from symbolic descriptions. When Parameter, Return, and Throws are set to bullet items followed by a colon:, they are segmented with the discussion in quick tips and help documents.
- Parameters:The beginning of a line with
- Parameter <param name>:
Start with a description of the parameters - Return values:The beginning of a line with
Returns:
Start with a description of the return value - Thrown errors:The beginning of a line with
Throws:
Along with a description of the exceptions that might be thrown, it is important to properly log errors because Swift does not type check thrown errors that are outside of error consistency.
In this article, we’ll basically use Swift code as an example. If your code is Objective-C, the format is a little bit different.
Take a keyword that returns a value. In Swift, we write -return:, but in Objective-C, you’ll write @return. For more details, see Apple’s HeaderDoc user guide.
/ * * Creates a personalized greeting for a recipient.
- Parameter recipient: The person being greeted.
- Throws: `MyError.invalidRecipient` if `recipient` is "Derek" (he knows what he did). - Returns: A new string saying hello to `recipient`. * /func greeting(to recipient: String) throws -> String { guard recipient ! = "Derek" else { throw MyError.invalidRecipient } return "Greetings, \(recipient)!" } Copy the code
If your method has more than one parameter, you can comment it out with Parameters:
/// Returns the magnitude of a vector in three dimensions
/// from the given components.
///
/// - Parameters:
/// - x: The *x* component of the vector.
/// - y: The *y* component of the vector. /// - z: The *z* component of the vector. func magnitude3D(x: Double, y: Double, z: Double) -> Double { return sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2)) } Copy the code
The other fields
In addition to the common fields above, Swift style Markdown defines several other fields:
type | |
---|---|
Algorithm/Safety Information | Precondition Postcondition Requires Invariant Complexity Important Warning |
Metadata | Author Authors Copyright Date SeeAlso Since Version |
General Notes & Exhortations | Attention Bug Experiment Note Remark ToDo |
They can be loosely organized as follows, with each field shown in the quick help as a bold title followed by a paragraph of text:
– Field name: The field description starts from the next line
The code block
Documentation comments also support embedding Code to demonstrate the correct use or implementation details of functionality. Insert code by adding three backquotes:
/ * * The area of the `Shape` instance.
Computation depends on the shape of the instance.
For a triangle, `area` is equivalent to:
` ` ` let height = triangle.calculateHeight() let area = triangle.base * height / 2 ` ` `* /var area: CGFloat { get } Copy the code
Or three antitilde:
/ * * The perimeter of the `Shape` instance.
Computation depends on the shape of the instance, and is
equivalent to:
~ ~ ~ // Circles: let perimeter = circle.radius * 2 * Float.pi // Other shapes: let perimeter = shape.sides.map { $0.length } .reduce(0, +) ~ ~ ~* /var perimeter: CGFloat { get } Copy the code
MARK / TODO / FIXME
In Objective-C, we use the preprocessor instruction #pragma Mark to divide functionality into meaningful, easy-to-navigate parts. In Swift, you can do the same with the comment // MARK:. And other tags we commonly use:
// MARK:
// TODO:
// FIXME:
// NOTE:
To show what these new tags can do in practice, here’s how to extend the Bicycle class to take advantage of the CustomStringConvertible protocol and implement the Description attribute.
// MARK: - CustomStringConvertible
extension Bicycle: CustomStringConvertible {
public var description: String {
var descriptors: [String] = []
. // FIXME: Use a distance formatter descriptors.append("...") // TODO: Allow bikes to be named? return descriptors.joined(separator: ",") } } Copy the code
Add a complete comment to a class
/// 🚲 A two-wheeled, human-powered mode of transportation.
class Bicycle {
/// Frame and construction style.
enum Style {
/// A style for streets or trails.
case road /// A style for long journeys. case touring /// A style for casual trips around town. case cruiser /// A style for general-purpose transportation. case hybrid } /// The style of the bicycle. let style: Style /// The size of the frame, in centimeters. let frameSize: Int /// The number of trips traveled by the bicycle. private(set) var numberOfTrips: Int /// The total distance traveled by the bicycle, in meters. private(set) var distanceTraveled: Double / * * Take a bike out for a spin. Calling this method increments the `numberOfTrips` and increases `distanceTraveled` by the value of `meters`. - Parameter meters: The distance to travel in meters. - Precondition: `meters` must be greater than 0. * / func travel(distance meters: Double) { precondition(meters > 0) distanceTraveled += meters numberOfTrips += 1 } } Copy the code
For the full 🚴♀️ document, click here.
Library project document generation
Let’s see how Jazzy can be used to generate API documentation for your project.
First, Jazzy supports documentation for Swift and Objective-C’s Xcode Project, and recently for SwiftPM. We will work our way up from a standalone Swift and ObjC project, to a hybrid project, and finally to generate private library documents based on CocoaPods.
Generate documentation for the Swift project
Jazzy defaults to parsing Swift code comments to generate documentation. Let’s start by trying to generate an HTML document for Alamofire.
Jazzy is a Gem dependency library. See Version Management Tools and Ruby Toolchain Environment for more information about gems.
[sudo] gem install jazzy
Copy the code
However, since Alamofire already has Jazzy dependencies in the project’s Gemfile, we’ll use Bundle Install to install it. Finally, export the document to the root directory of the project through -o Docs. The complete command is as follows:
$ git clone https://github.com/Alamofire/Alamofire
$ cd Alamofire
$ bundle install
$ bundle exec jazzy -o Docs
Copy the code
The effect of the generated document:
By default, Jazzy reads the contents of readme. md, readme. markdown, readme. mdown, and README documents in the project as the contents of the index page.
For Swift Module projects, Jazzy automatically looks for project in the project root directory when generating documents, then executes XcodeBuild or Swift Build to generate Clang AST, and SourceKit to generate comment documents.
For SwiftPM enabled projects, we can also generate documentation by specifying –wift-build-tool:
$ bundle exec jazzy \
-o Docs \
--module Alamofire \
--swift-build-tool spm \
--build-tool-arguments -Xswiftc,-swift-version,-Xswiftc,5
Copy the code
Generate documentation for objective-C projects
Objective-c project document generation requires several more parameters. Here we use AFNetworking as an example.
Clone code to add Jazzy dependencies to Gemfile in AFNetworking:
source "https://rubygems.org"
gem "fastlane"
gem "cocoapods"
gem "jazzy"
gem "xcode-install" Copy the code
Next, install Jazzy to generate the docs document:
$ bundle install
$ bundle exec jazzy \
-o Docs \
--objc \
--umbrella-header AFNetworking/AFNetworking.h \
--framework-root AFNetworking Copy the code
- –objc: Specifies generating documents for Objective-C
- — umbrell-header: specifies the Objective-C framework
Umbrella header
The path - –framework-root: Specifies the objective-C framework path
Generate documentation for Swift & Objective-C hybrid projects
Jazzy’s support for the hybrid project has not been very friendly so far. To generate a document with mixed code comments, we need to generate jSON-formatted intermediates and pass them to Jazzy to generate the complete document. The tool SourceKitten is needed.
Let’s start with the way documentation is generated based on a composite project:
#Outputs the SourceKitter Swift document data to JSON
sourcekitten doc -- -workspace MyProject.xcworkspace -scheme MyScheme > swiftDoc.json
#Output SourceKitter objective-C document data to JSON
sourcekitten doc --objc $(pwd)/MyProject/MyProject.h \
-- -x objective-c -isysroot $(xcrun --show-sdk-path --sdk iphonesimulator) \ -I $(pwd) -fmodules > objcDoc.json #Merge Swift and Objective-C JSON and output the document jazzy --sourcekitten-sourcefile swiftDoc.json,objcDoc.json Copy the code
Of course, Jazzy has many other parameters that are not covered here. If you are interested, you can check the official documentation or use Jazzy –help
conclusion
- This article showed you how to write Swift style code comments to Apple standards and how to generate simple HTML documents based on Jazzy.
- You probably don’t pay much attention to the specification and writing of the documentation, but when you need to look at the system framework or open source API, the description in the notes is not enough, so start writing the documentation now.
- A good document can not only record the implementation ideas and principles of the code, but also better transfer the core ideas to the person who takes over, and better maintenance.
- Basically, good open source libraries require very detailed documentation, such as Alamofire and QMUI.
Knowledge points and problems sorting
Here are four questions to determine if you have already mastered the article, and if not, add it to your bookmark and read it again:
-
What’s the difference between Objective-C and Swift code comments?
-
What is the difference between commenting a method with multiple arguments and a single argument to a method?
-
What Markdown formats are supported for code comments?
-
How many modes of document generation does Jazzy support?
This article is formatted using MDNICE