> ## Content Index
> Fetch the complete content index at: https://williamboles.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Producing Documentation with appledoc
- URL: https://williamboles.com/using-appledoc-to-produce-documentation/
- Published: 2012-08-22T19:13:00.000Z
- Updated: 2026-10-04T21:52:47.000Z
- Description: Some code is inherently murky, and good naming practices can only take us so far — looking at you, animation code. Where the intent of code is hard to decipher, high-quality developers use documentation to overcome that murkiness. Here, we look at how to use appledoc to produce documentation.
- Author: William Boles
- Tags: Documentation

It's late at night, you're tired, and you're stuck on a complex problem you just can't seem to solve. In your moment of need, you turn to Google, and after unleashing your expert search skills, you spot it - a GitHub project shimmering on the horizon that looks like it solves your problem. You hit that clone button faster than is decent and open the project. The solution is close, but not quite right for your situation. As you attempt to modify it, you hit wall after wall of misunderstanding. With only the code to go on, what looked like an oasis slowly fades, revealing itself to be nothing more than a mirage. Demoralised and even more tired, you try a different approach.

What a missed opportunity - for both you and the original developer.

When we share our code, we often do so hoping it will prove useful to someone else. But code alone is rarely enough. The next developer needs the thinking behind the code. They need context. Documentation is that context. But it's not just a tool to help the next developer - it's also a reflection point. If you sit down to describe a type or method and struggle to explain it clearly, that's a signal that something isn't right. It's probably doing too much. The overly long comment block becomes a refactoring prompt as much as a communication tool. So write documentation for the next developer, but also write documentation to enable you to write better code.

So how do we build that oasis and avoid the mirage? Let's start with a tool that makes producing documentation straightforward - [appledoc](https://github.com/tomaz/appledoc/?ref=williamboles.com).

![Photo of an oasis](https://storage.ghost.io/c/b9/b4/b9b42214-5933-4584-8e56-9ee8ca21d23b/content/images/size/w1000/2026/02/photo-of-an-oasis-min.jpg)

> `appledoc` hasn't seen active development since 2021, and the project is currently looking for contributors. It remains a solid tool for Objective-C projects, but there may now be better alternatives out there.

## Getting to know appledoc

`appledoc` is a command-line tool that turns your Objective-C source code comments into Apple-style HTML documentation and Xcode docsets - helping us write better code by writing documentation. Add specially formatted comments to your code, point `appledoc` at your project, and it handles the rest - parsing your source to produce documentation that looks and feels like Apple's own.

It can be installed via [Homebrew](https://brew.sh/?ref=williamboles.com):

```
brew install appledoc
```

`appledoc` is deceptively simple - it has very few keywords and operates mainly by string matching. Before we delve into an example, let's look at the syntax that powers `appledoc`.

`appledoc` works by parsing `/** */` comment blocks placed above declarations.

> Note the extra opening `*` to differentiate an `appledoc` comment from a standard Objective-C comment.

The text that sits within an `appledoc` comment block can be:

- Multi-lined.
- Contain lists.
- Formatted, e.g. use `* *` to style the enclosing text as bold.
- Contain URLs to external sources.

Each type can have the following documentation sections:

1. Overview.
2. Discussion.
3. Task (Properties) list.
4. Instance methods.
5. Class (Type) methods.
6. See also.

> Not all these sections need to be present, e.g. a type without class methods won't have that section.

The keywords in `appledoc`:

| Keyword  | Description                                                                         |
| -------- | ----------------------------------------------------------------------------------- |
| @param   | Describes the name and purpose of a method parameter                                |
| @return  | Describes the method's return value                                                 |
| @see     | Populates the "See also" section for the type or method with a link to another type |
| @warning | Describes a warning about the method                                                |
| @bug     | Describes a bug within that method                                                  |

`appledoc` extracts these values when building the documentation and provides a different visual representation for each one.

Now, let's look at how we can use `appledoc` to write documentation.

## Adding Signposts

In this example, we are going to add documentation to two types that are part of a camel racing game: `ADECamel` and `ADETrack`. Undocumented, the interface of these types looks like:

```
@interface ADECamel: NSObject

@property (nonatomic, assign) NSUInteger currentSpeed;

- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

- (void)run;

@end

@interface ADETrack: NSObject

@property (nonatomic, strong) NSArray * camels;

- (ADECamel *)race;

@end
```

Let's start revealing the mystery of these types, starting with `ADECamel`.

### Classes

A class can include a single `Overview` section describing its purpose.

To add an `Overview` section, we add a comment block directly above the `@interface` declaration:

```
/**
 Represents a camel competing in a race.
 */
@interface ADECamel: NSObject

//Omitted other functionality

@end
```

An `Overview` can be spread over multiple lines:

```
/**
 Represents a camel competing in a race.

 Tracks the camel's current speed as the race progresses and provides access to race information such as the camel's assigned race number and rider.
 */
@interface ADECamel: NSObject

//Omitted other functionality

@end
```

> To keep the examples focused, I've omitted any functionality that isn't directly related to where the documentation is being added.

Now that we have seen class documentation, let's look at property documentation.

### Properties

Property documentation follows the same pattern as class documentation:

```
@interface ADECamel: NSObject

/**
 The camel's current speed in km/h. Updated throughout the race as the camel accelerates and decelerates.
 */
@property (nonatomic, assign) NSUInteger currentSpeed;

//Omitted other functionality

@end
```

If a property doesn't have a comment block, `appledoc` won't pick them up as a class "Task" or include them in automatic cross-references (we'll see more on that later).

Now that we have property documentation, let's look at method documentation.

### Methods

A method can have multiple sections in its documentation. Let's start by adding an `Overview` section:

```
@interface ADECamel: NSObject

//Omitted other functionality

/**
 Designated initialiser.
 */
- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

//Omitted other functionality

@end
```

In method documentation, the first line becomes the `Overview` section. Anything after a blank line becomes the `Discussion` section:

```
@interface ADECamel: NSObject

//Omitted other functionality

/**
 Designated initialiser.

 Creates a camel object ready to compete in a race.
 */
- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

//Omitted other functionality

@end
```

The `Discussion` section does not appear in the `Quick Help` option in `Xcode` (only in the docset), so don't put anything critical into this section - use it as an opportunity to expand on points already made.

> By default, the `Overview` section is part of the `Discussion` section, but if you don't want that, use the `--no-repeat-first-par` flag when producing your documentation - we'll see how to use flags soon.

It's looking better, but we are still missing some details about the method, so let's add in documentation for the parameters:

```
@interface ADECamel: NSObject

//Omitted other functionality

/**
 Designated initialiser.

 Creates a camel object ready to compete in a race.

 @param raceNumber the camel's assigned race number
 @param topSpeed the camel's maximum speed in km/h
 @param rider the name of the camel's rider
 */
- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

//Omitted other functionality

@end
```

> The @param  value must match the method signature parameter name exactly. A mismatch won't stop the build, but it will trigger a validation warning and may break cross-referencing.

Let's add the final missing piece of documentation for this method - the return type:

```
@interface ADECamel: NSObject

//Omitted other functionality

/**
 Designated initialiser.

 Creates a camel object ready to compete in a race.

 @param raceNumber the camel's assigned race number
 @param topSpeed the camel's maximum speed in km/h
 @param rider the name of the camel's rider
 @return a camel object configured for the race
 */
- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

//Omitted other functionality

@end
```

With the initialiser documented, let's finish the `run` method by adding a `@warning`:

```
@interface ADECamel: NSObject

//Omitted other functionality

/**
 Starts the camel moving.

 @warning *Warning:* Once started, a camel will never stop running.
 */
- (void)run;

@end
```

Now that we have some documentation, let's talk about the superpower of `appledoc`: automatic cross-referencing.

### Cross-referencing

Good documentation lets you move through it. `appledoc` enables this with automatic cross-referencing by turning recognised type names into links. We don't need to use any keywords to enable this functionality; we just need to ensure that the type string exactly matches the type. In our `ADETrack` implementation, we have a method that returns `ADECamel`, which will result in cross-referenced documentation being produced:

```
@interface ADETrack: NSObject

//Omitted other functionality

/**
 Starts the race and returns the winning camel.

 @return the ADECamel that won the race
 */
- (ADECamel *)race;

@end
```

In the `@return` statement, we simply mention `ADECamel` and `appledoc` will do its magic.

> `appledoc` can't link through to Apple's own documentation, so if, for example `UIAlertViewDelegate` was mentioned in the documentation, the string `UIAlertViewDelegate` won't become a link.

Finally, let's see everything together:

```
/**
 Represents a camel competing in a race.

 Tracks the camel's current speed as the race progresses and provides access to race information such as the camel's assigned race number and rider.
 */
@interface ADECamel: NSObject

/**
 The camel's current speed in km/h. Updated throughout the race as the camel accelerates and decelerates.
 */
@property (nonatomic, assign) NSUInteger currentSpeed;

/**
 Designated initialiser.

 Creates a camel object ready to compete in a race.

 @param raceNumber the camel's assigned race number
 @param topSpeed the camel's maximum speed in km/h
 @param rider the name of the camel's rider
 @return a camel object configured for the race
 */
- (id)initWithRaceNumber:(NSUInteger)raceNumber
                topSpeed:(NSUInteger)topSpeed
                   rider:(NSString *)rider;

/**
 Starts the camel moving.

 @warning *Warning:* Once started, a camel will never stop running.
 */
- (void)run;

@end

/**
 Represents a race track and manages the camels competing on it.

 Provides the ability to start a race and determine the winner from the competing camels.
 */
@interface ADETrack: NSObject

/**
 A collection containing the camels competing in the race.
 */
@property (nonatomic, strong) NSArray * camels;

/**
 Starts the race and returns the winning camel.

 @return the ADECamel that won the race
 */
- (ADECamel *)race;

@end
```

> Everything above applies equally to class methods, protocols and categories.

### Building the Oasis 🌴

There are two ways to drive `appledoc`:

1. Command line with flags.
2. Command line and [plist](https://en.wikipedia.org/wiki/Property%5Flist?ref=williamboles.com) containing flags.

Both approaches use the same flags:

| Flag               | Description                                                                                                                                             |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \--project-name    | The name of the documentation. This name is case sensitive, so "AppledocExample" and "appledocExample" will produce two separate sets of documentation. |
| \--project-company | Company name.                                                                                                                                           |
| \--company-id      | Reverse domain, expanded to form the docset Bundle ID, e.g. com.williamboles becomes com.williamboles.AppledocExample.docset.                           |
| \--output          | The folder used to create the docset before it's moved to Xcode.                                                                                        |

> The above flags are the minimum flags needed for `appledoc` to produce documentation. `appledoc` has a lot more built-in flexibility, just waiting for you to explore it.

#### Command Line with Flags

From the project folder, run:

```
appledoc --project-name AppledocExample --project-company "WilliamBoles" --company-id com.williamboles --output ~/help .
```

> Don't forget the `.` \- it tells `appledoc` to look in the current directory.

#### Command Line with Plist

The plist approach uses the same flags, just stored in a file - handy if you're running `appledoc` regularly and don't want to retype them each time.

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>--company-id</key>
<string>com.williamboles</string>
<key>--project-company</key>
<string>WilliamBoles</string>
<key>--project-name</key>
<string>AppledocExample</string>
<key>--output</key>
<string>~/help</string>
</dict>
</plist>
```

From the project folder, run:

```
appledoc .
```

> Don't forget the `.` \- it tells `appledoc` to look in the current directory for the plist.

## Don't be the Mirage

Someone, somewhere, will hit a problem that your code solves. It might be a teammate, a stranger on the internet, or you at midnight six months from now. The difference between your project being the mirage and being the oasis is documentation. Give them the thinking behind the code. Give them the context. Let them modify, adapt, and build on what you've made.

Don't be the missed opportunity.