UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

How to document your project with DocC

Markdown-powered documentation is now just a click away.

Paul Hudson       @twostraws

DocC is Apple’s new tool for building beautiful, interactive, and native-feeling documentation right from your code, and it integrates smoothly into both Xcode and the web.

In this article I’m going to walk you through the fundamentals of using it in two different ways: building documentation for a framework, and adding articles that provide more depth. Along the way, you’ll see some places where DocC works brilliantly, and also some places where it doesn’t really work like I’d expect at all. And that’s okay – it’s only the initial release, after all.

Before I start, though, there are some basics:

  • You need to have Xcode 13 installed in order to have access to DocC.
  • It supports only Swift at this time. They have already received requests to add Objective-C support, and in the long term I hope they’ll add support for other languages too.
  • In case you were curious, DocC is short for “Documentation Compiler”, and it’s pronounced with two equally stressed syllables – “Doc-See” as opposed to “doxy”.
  • Xcode is packed with lots of major new features – it’s another real stand out year, and I hope the team are feeling really proud. You can find out more in my article What’s new in Xcode 13.

Please keep in mind I’m using Xcode 13 beta 1, so it’s all early days at this point – I expect DocC to get polished up a lot before the final release later this year.

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

First, what DoC is not

The first thing I did when trying out DocC is what I expect most app developers would do: I opened up one of my projects to see what DocC would make of it. In my case, that was Unwrap – it’s a good size of project with various dependencies, and matches the kind of thing many app developers will be working with.

If you want to try this in your own app project, just go to the Product menu and choose Build Documentation. It might take a minute or two to complete, but when it’s finished you’ll see Apple’s Developer Documentation window appear with its results – your app’s documentation, living right alongside Apple’s own frameworks.

Except it isn’t, at least not in the way I had hoped. You see, at this time DocC supports only frameworks and packages, which means it picked out only the external packages used by my app as opposed to all the app code itself. This is a bit of a shame, to be honest, because the overwhelming majority of us work on actual app projects, and when someone new joins a team it would be great to give them some clear, readable documentation to help on-ramp them.

If you’re in this situation, I would suggest looking to break your project down into smaller packages – that should allow DocC to scan and document them correctly.

My next attempt was with my Sitrep project, which is a package. I felt sure this would work much better, but again hit problems: DocC will only scan for things that are available externally to the package, so most of Sitrep is ignored. This is not a bug, but rather another disconnect between my head and the way DocC works – it’s very tightly focused on people who are using a package or framework, as opposed to people building that package or framework, or indeed an app.

If you ever used something like Jazzy to generate your documentation, it had the same public limitation by default, but at least there you could ask it to expose internal values for when you actually wanted it.

Working with Markdown documentation

Once I had figured out what DocC wasn’t, it was much easier to find a project that would definitely work well: SwiftGD, my open-source image manipulation package that lets you create graphics with server-side Swift.

Although this package does have some internal functionality, it’s mostly exposed to the world as public API and that’s exactly what DocC is looking for. And out of the box – just going to Product > Build Documentation – we actually get something pretty good:

  • All the classes, structs, and enums are listed, along with their summaries.
  • Selecting any of them will show
  • You can open up any of them in the navigator to reveal their properties and methods
  • Lots of clickable links between methods and properties

In fact, the documentation is pretty much indistinguishable from Apple’s own developer documentation – even down to showing “No overview available” when something is missing.

All this works out of the box because of documentation comments, which are Xcode comments written in a specific format: either using triple slash, ///, or by starting with /**.

Markdown comments are not the same as the regular inline comments you add to particular code, so you need to use them differently:

  • Regular comments, // and /*, are used to mark what your code is trying to do, adding explainers for people who want to understand or modify that piece of code.
  • Documentation comments, /// and /**, are used to mark how your code should be used, explaining what its parameters are, what it returns, and more.

Xcode has treated documentation comment specially even before DocC – they get pulled out and shown in the Quick Help pane, as well as in the autocomplete popup.

The best way to get started with Markdown documentation is to select a function you want to document, press Shift+Cmd+A to bring up the code actions balloon, then select Add Documentation. If you’re like me and prefer keyboard shortcuts, use Opt+Cmd+/ to get the same result.

This shortcut is particularly useful before functions, because it adds information about parameters and return type automatically. But once you’re inside a documentation comment, all the Markdown you’d expect is available to you:

Place text in `backticks` to mark pieces of code.
DocC also supports ``doubleBackticks`` to create links to other parts of your documentation, and paths such as ``SomeClass/someProperty`` to be more specific.
* Write bullets by starting with an asterisk then a space.
    * Indent your asterisks to create sublists
1. You can write numbered listed by starting with 1.
1. Subsequent items can be numbered higher if you want, but you can also number them 1. and Xcode will renumber them for you.

# Headings start with a # symbol
If you need subheadings, use ##, ###, and so on.

For links, [place your text in brackets](and your link in parentheses).
Write *one asterisk* around words to make them italic
Write **two asterisks** around words to make them bold
Write ***three asterisks*** around words to make them bold and italic at the same time

That’s all just regular Markdown syntax, but there are some specific things that both Xcode and DocC look for, and if you add those it will really enrich the documentation you provide.

For example, the Returns keyword lets you specify what value the caller can expect back when the function runs successfully. This isn’t just the data type – Xcode can figure that out for itself – but instead what’s in the value. So, for example you might say this:

- Returns: A string containing a date formatted as RFC-822

There’s also the Parameter keyword, which lets you specify the name of a parameter and describe what it contains. You can include as many Parameter lines as you have parameters, just listing them each out along with what they actually are:

- Parameter album: The name of a Taylor Swift album
- Parameter track: The track number to load

Again, Xcode can figure out the type of the parameter, so you’re just documenting what it represents.

There’s also the Throws keyword, where you can provide a comma-separated list of the error types that can be thrown by the function:

- Throws: LoadError.networkFailed, LoadError.writeFailed

There are others, but in practice one of the most important pieces of text you’ll use is the line break – literally just pressing return. This is because the first lines of your comment are used as the summary for your function, but when you leave one clear line break followed by more text that subsequent text gets used as the detailed discussion of your code.

Adding a Documentation Catalog

So far we’ve just relied on plain documentation comments to get good results, but DocC lets us go a lot further by adding custom articles that really bring our documentation to life.

You see, everything we have so far makes for a good reference, which is perfect for the times you want to read about a specific type, property, or method. But it’s less good at actually introducing what our framework is trying to do – providing an introductory reference, explaining how the parts fit together, or pointing out particularly important concepts.

We can fix that by adding a documentation catalog to our project, which lets us provide custom documentation that sits outside of our main codebase.

To do this in your own project, right-click on your package’s directory in the project navigator, then choose New File. If you scroll down to the Documentation section you’ll see Documentation Catalog – select that and click Next, and Xcode will create the catalog for you immediately.

Xcode will create the documentation catalog for you, called Documentation. Inside there it will create a single Markdown file, also somewhat unhelpfully called Documentation, as well as a Resources directory where you can place assets such as screenshots.

To get started, try changing that initial Markdown document so that it represents the homepage for your whole package. To do that, change the line at the very top to your package name, similar to this:

# ``SwiftGD``

You can then go ahead and write free Markdown below, but carefully – you get control over your summary, overview, and all the topics you want to list, but you should follow a particular format:

  • Leave the “Topics” title alone. If you change its name the output will look weird, and if you try to add another second-level heading it won’t work.
  • The third-level headings – “Group” by default – become the left-hand-aligned headings that sit next to things you want to pick out.
  • Inside the third-level headings you can place bulleted links to articles you want to mention. Don’t try and place anything other than links to other things in there, because it won’t work.

In terms of what you might put into the third-level headings, you can either link to types into your package, or link to other documentation articles you’ve written.

Important: Remember, links are like regular code Markdown except use double backticks.

For example, in my SwiftGD project I might want to pick out some specific types that are important like this:

- ``Color``
- ``Rectangle``

Or I might want to point out specific properties on a type, like this:

- ``Rectangle/point``
- ``Rectangle/size``

You might notice how Xcode is smart enough to do code completion here, which is really helpful when working with methods because you just type them out in full, complete with parameter names:

- ``Image/applyInterpolation(enabled:currentSize:newSize:)``

At build-time these links get expanded to full documentation references that click through to the full page, and also providing any summary text below if possible.

Once you’ve made your changes, rebuild your documentation to see how it looks – all being well it should all be there.

Important: If you find your changes aren’t visible, you might find you need to increase the swift-tools-version in your Package.swift file. SwiftGD was set to 5.0 and so didn’t work well with DocC, but bumping that up to 5.5 solved the problem.

Before we move on, I want to show you how smart DocC is with regard to images, because just like using an asset catalog it takes a lot of the hassle away as long as you help it along.

To add an image, first give it a name that clarifies what it’s for. Apple recommends using @2x images across the board, so at the very least you need to provide SomeScreenshot@2x.png. However, if you want one image for light mode and another for dark, you can provide the dark variant by putting “~dark” before the @2x to make SomeScreenshot~dark@2x.png.

These kinds of magic filenames were common in iOS development before we had access to asset catalogs, and honestly I’d like to see them here too – managing assets gets tricky in non-trivial project, and any tools that can help are welcome.

Anyway, to embed that image in an article, use standard Markdown image syntax:

![The Hacking with Swift logo](hws.png)

In that small snippet, notice first how we don’t need to add image variant data to the filename – just plain old hws.png is fine – and also that it’s important to add a description to VoiceOver can describe the image contents.

If you go ahead and build your documentation again, you should see the picture in place. In beta 1, it seems that the switch between light and dark mode isn’t quite flawless – you might find you need to switch back and forward between articles to get the image to update.

Where these articles become even more useful is when you start adding other articles to your document catalog, because you can add as many more articles as you want to your catalog and link them together.

To try this out, right-click on your documentation catalog in the project navigator and add a new file. You’ll see there is both an Article File and an Extension File, but this is a bit confusing because as far as I can see they both make the same thing – they both make a Markdown file with no special build options.

The only actual difference is the template that is generated, because documents with a type in the top-level header are considered to be documentation specifically for that type. Think of it a bit like a Swift extension: you could put all your code in the original type, but it’s often easier and more logical to split things up. In documentation terms, you could put very long documentation comments into your code if you wanted, but these extension files mean you don’t need to because you can move them over to pure Markdown instead.

For now, go ahead and choose Article File, which lets us generate another free-text article. Just like our original article this can contain all the Markdown you want, including links to other articles and API you want to mention.

The name you give to this new article matters, because it affects how you reference it elsewhere. You can use spaces to get more natural names if you want; they will just get replaced with dashes at build time.

Anyway, now that we have a second article you can go ahead and add all the content you want to it, but more importantly you can link to that article elsewhere in your documentation. This is done using a special link type:

<doc:New-Article>

Again, Xcode is going to autocomplete this for you, and it will even check if you add a broken link by accident – you’ll get a warning right there in your Markdown file. (PS: Xcode folks: could this be an error? Thank you!)

Distributing your work

All this time we’ve been pushing our work directly into Xcode’s documentation viewer, but that’s just temporary – as soon as you close Xcode it will disappear from there. It’s helpful while you’re working to know that it all gets swept away as soon as you quit, but obviously at some point you’ll have something you actually want to share with the wider world.

You can if you want build your documentation package automatically using xcodebuild, but you can also right-click on it directly inside the documentation viewer and choose Export. Once you do that you’ll get a “.doccarchive” package – it’s nothing fancy, just a directory with need to read your documentation in Xcode or on the web.

So, you could now zip that up and mail it to someone for review, or if you want to publish it online. Now, if you’re anything like me you’re probably aware that Python has a built-in web server module that’s really helpful for quick testing – you would run python3 -m http.server in the directory.

However, that doesn’t work: the package they generate requires a very specific server configuration. It needs to be served at the website root, with specific redirects in place in order to work. Honestly, if Apple hadn’t provided the correct Apache htaccess instructions I wouldn’t have managed to get it working.

For your reference as much as mine, here they are:

RewriteEngine On
RewriteRule ^(documentation|tutorials)\/.*$ YourPackage.doccarchive/index.html [L]
RewriteRule ^(css|js|data|images|downloads|favicon\.ico|favicon\.svg|img|theme-settings\.json|videos)\/.*$ YourPackage.doccarchive/$0 [L]

Once you have that in a htaccess file on your web server, obviously adjusted so that YourPackage.doccarchive matches your filename, you should be able to copy across the documentation archive and have everything more or less work.

To try it out, I set up http://docc.hackingwithswift.com – it won’t actually work as a link, because it’s a local web server running on my Mac using MAMP. Although the archive needs to be served from the website root, it doesn’t take over the rest of your site – you still have to serve the rest of the pages yourself, and it will just take care of those such as http://docc.hackingwithswift.com/documentation/SwiftGD in my case.

The end result looks basically identical to Apple’s own hosted documentation, with the exception of light and dark mode controls displayed at the bottom. On the one hand that’s great, because it’s a familiar environment to a lot of people, but on the other hand I think there will be some loud calls for customization options.

As things stand, the generated documentation is effectively a sealed box – the Apache rewrite rule references a theme-settings.json file, which suggest some customization is going to come, but I don’t know to what extent. I can imagine bigger companies wanting their corporate branding integrated, or their regular site navigation.

The web pages are also very heavy on the JavaScript and honestly I’m not sure why – the reference documentation and articles are simple beasts, and if DocC could flatten them to plain HTML then I imagine the rewrite rules would just go away. At the same time, Apple’s own documentation system is completely inaccessible with JavaScript turned off, so I don’t hold out a great deal of hope here.

Where next?

It’s worth reiterating what I said at the beginning: this is only beta 1 of Xcode 13, so there’s a great deal of time for things to evolve before we hit a final release, and even then it’s just the beginning – I expect DocC to continue to evolve and grow in the future as more features are added.

For example, if you query xcodebuild on the command line it looks like experimental documentation coverage is somewhere in there, which would give DocC the ability to report back how much of our code is fully documented.

We’re also yet to see how DocC adapts to other programming languages, not least Objective-C. Apple folks on Twitter and the developer forums have said it’s a priority, which would go a long way to helping DocC achieve broader adoption.

There are already tools out there that do similar tasks, but none are quite so integrated. I spoke to JP Simard, who created the widely popular Jazzy tool back in 2015 as well as many others – it does a similar job to DocC, except is open source, community-driven, supports Objective-C, and works with private symbols.

As JP pointed out, the strength of DocC is that it goes beyond just documentation generation:

“I’m really happy to see Apple providing a code documentation generation tool, and it’s more than just the tool – it’s the viewer UI, it’s Xcode integration with the Build Documentation command, Quick Help integration, and it’s a CLI too. The output has a static HTML site you can host yourself and view in a web browser, but even better all the data that is shown in the rich UI is also accessible in a machine-readable JSON format so existing documentation generation tools like Jazzy and SwiftDoc could easily add support for ingesting that data.”

One interesting advantage that DocC has is its ability to generate interactive tutorials identical to those Apple used for SwiftUI. Although they aren’t something I can see myself using just yet, I’ll certainly be watching to see if the community shows interest in this format.

Apple has announced that DocC will be open sourced by the end of the year, and I’m expecting uptake to be pretty brisk. Heck, there’s already a project in place to support cloud-based DocC archives, taking away all the hassle of hosting completely.

DocC was a really pleasant surprise this year, and the team have done a good job of building really tight integration with the rest of Xcode. I’m confident the few hiccups I’m hitting right now will get ironed out before release, and we might even see a few extra little features sneak in too.

Are you planning to move over to DocC, or is it missing a feature you’re relying on? Let me know on Twitter @twostraws!

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.