Cocoa Documentation.png

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

Cocoa code comments and documentation generation directory.png

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.

HeadDoc style documents

With the release of WWDC 2014, the developer documentation was overhauled and redesigned to include Swift and Objective-C support.

Apple’s new style of documentation

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 + /

Shortcuts for adding comments in Xcode

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
Prompt effect for Swift comments

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 numeralsOne, 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

Markdown annotation style effect.png

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 withReturns:Start with a description of the return value
  • Thrown errors:The beginning of a line withThrows: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 segmentation effect
// 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:

Jazzy generates document effects.png

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 frameworkUmbrella headerThe 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:

  1. What’s the difference between Objective-C and Swift code comments?

  2. What is the difference between commenting a method with multiple arguments and a single argument to a method?

  3. What Markdown formats are supported for code comments?

  4. How many modes of document generation does Jazzy support?

This article is formatted using MDNICE