SwiftGen Tutorial for iOS

Learn how SwiftGen makes it easy to get rid of magic strings in your iOS projects. By Andy Pereira.

5 (3) · 1 Review

Download materials
Save for later
Share

As a mobile developer, you might feel like you encounter magic daily. The lines of code you write get converted into apps that people all over the world can use. The tools Apple provides help make that magic come to life and make your life easier. As you journey further into software development, you might realize there’s one piece of magic you don’t like: the magic string.

Type safety, the concept that variables can only be of a specific type, provides developers with guardrails that keep their programs safe. Magic strings, however, introduce unsafe code into those applications. What is a magic string? In iOS development, you’ve encountered these many times. An example looks something like the following:

let color = UIColor(named: "green-apple")
self.title = "Welcome!"

This example shows "green-apple" and "Welcome!" written as strings directly in your code. It’s not a stretch to say all developers have found themselves guilty of this practice sometimes.

In fact, in iOS development, you don’t have much of a choice. Out of the box, Xcode doesn’t provide a way to avoid this practice.

Those who’ve worked in Android might find themselves cringing at code like this. Android development environments have a mechanism that converts app resources, such as strings, colors, images and fonts, into type-safe variables. There are many benefits to this. It:

  • Reduces the risk of misspelling.
  • Prevents unnecessary duplication of resources.
  • Provides resource checking at compilation time.
  • Helps when cleaning up old resources.
  • And more!

As stated, iOS and macOS developers don’t have access to a system that provides this resource type-safety out of the box.

Fortunately, there’s SwiftGen, a code generator for getting rid of magic strings in your app. Available as an open-source library on GitHub, you can add this to your iOS and macOS projects to bring type safety and compilation-time checking of all your assets.

In this tutorial, you’ll learn how to:

  • Set up your project with SwiftGen.
  • Define which assets you want to convert.
  • Define where the generated code will live.
  • Create templates that allow SwiftGen to generate code that will work with SwiftUI for fonts and colors.

Getting Started

To get started, click the Download Materials button at the top or bottom of this tutorial.

There are a few ways you can install SwiftGen to work with your environment:

  • CocoaPods
  • Homebrew
  • Mint
  • Directly download a zipped release

In this tutorial, you’ll use CocoaPods to manage SwiftGen.

Note: If you don’t have CocoaPods, don’t worry — the starter and final projects already have the dependency downloaded. :]

Open the workspace, named DrinksUp!.xcworkspace. Because this project uses CocoaPods, you won’t be able to work with DrinksUp!.xcodeproj directly.

Take a moment to look around in Xcode. The project is already in a completed state but uses strings to reference fonts, colors, images and strings. You’ll convert all these by the end of the tutorial.

Build and run and get familiar with the app.

DrinksUp initial launch screen

The app, DrinksUp!, is a way to track fun drinks you and your family have tried while visiting restaurants or at home.

Setting up SwiftGen

Start by opening Terminal and navigating to your starter project’s root directory. Next, enter the following command in Terminal:

./Pods/SwiftGen/bin/swiftgen config init

This will generate a configuration file, named swiftgen.yml, at your project root. If this file opens automatically in Xcode, go ahead and close it.

Next, in your project workspace, go to File ▸ Add Files to “DrinksUp!”…. Find swiftgen.yml. Be sure to uncheck Copy items if needed and select Create folder references.

Add SwiftGen.yml without copying file

Click the Add button. When done, you should see swiftgen.yml at the top of the Project navigator, like below:

SwiftGen yml file in Project navigator

Note: You can move this file to sit in the same place as shown, if Xcode didn’t add it the same way.

This file is where you’ll place the instructions telling SwiftGen which files you want to convert into generated code. The file type, YML, indicates it’s using YAML for its syntax. If you haven’t used YAML before, it’s simply a more readable way to view serialized data. You can think of it as JSON, simplified.

Now, replace the entire contents of swiftgen.yml with the following:

# 1
input_dir: DrinksUp!/
# 2
output_dir: DrinksUp!/Generated/

Here’s what you added:

  1. You’ve declared a variable, input_dir, or the input directory. This tells SwiftGen the root folder to navigate against for all the file paths you’ll add soon.
  2. Another variable that defines the output directory of the generated Swift files. By doing this, you make it easier to keep track of all the SwiftGen files.

Adding a Build Phase

To run SwiftGen, you’ll need to add a new build phase to your project. To do this, select your project in the Project navigator, select Build Phases. Select + and choose New Run Script Phase.

Add new run script to project

Rename the script to SwiftGen by double-clicking the current name, Run Script. Next, add the following inside the text field of the script:

if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]]; then
  "${PODS_ROOT}/SwiftGen/bin/swiftgen"
else
  echo "warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it."
fi 

Finally, reorder the script to sit just after the script name [CP] Check Pods Manifest.lock. Your Build Phases should now look like the following:

SwiftGen script added and ordered

Build and run. If everything is set up properly, you shouldn’t have any errors. You won’t have anything in your Generated folder yet. That comes next.

Converting XCAssets

Now, you’re ready to start removing strings from your project! The first step will be to have SwiftGen generate code for XCAsset files in the project. Open swiftgen.yml and add the following to the end of the file:

## XCAssets
# 1
xcassets:
  # 2
  inputs:
    - Assets.xcassets
    - Colors.xcassets
  # 3
  outputs:
    # 4
    templateName: swift5
    # 5
    output: XCAssets+Generated.swift

Here’s what each of these lines means:

  1. Each file type, or template, you want to convert with SwiftGen requires an entry at the root level of swiftgen.yml. Here, this indicates you want SwiftGen to convert files that are an XCAsset.
  2. This list indicates which files SwiftGen should limit its conversion to.
  3. You need to tell SwiftGen how to generate the output.
  4. You must provide a template name. Here, swift5 is a default template provided by the SwiftGen team. You’ll learn how to use your own templates later.
  5. Finally, you provide the file name you want your new Swift code to generate into. Remember, you defined output_dir at the top of the file, which means it will output into Generated/XCAssets+Generated.swift.

Build and run. If you didn’t encounter any errors, your code generation worked!

Adding File

Expand the Generated group in Project navigator. At the moment, you still won’t find your new file. To add it, right-click Generated and select Add Files to “DrinksUp!”….

Add generated file to project

Select XCAssets+Generated.swift. Ensure Copy items if needed is not selected, then click Add. Now, open XCAssets+Generate.swift and look around. You’ll see the enum Asset. In the enum, you’ll find further enumerations defined that match the XCAsset catalogs you defined. For example:

  • Assets: Each of the images included in the project now has a static property defined.
  • Colors: All the app’s colors also have static properties available to reference.

Open Assets.xcassets. Notice there’s a group of images named launch-assets. But Assets declared all the static image properties at the same level. SwiftGen can maintain this organization for you but doesn’t do so by default. Open swiftgen.yml and replace the entire xcassets entry with the following:

## XCAssets
xcassets:
  inputs:
    - Assets.xcassets
    - Colors.xcassets
  outputs:
    templateName: swift5
    # 1
    params:
       # 2
       forceProvidesNamespaces: true
       # 3
       forceFileNameEnum: true
    output: XCAssets+Generated.swift

Here, you take advantage of SwiftGen’s ability to customize your code output by doing the following:

  1. Define params on your outputs node.
  2. forceProvidesNamespaces: This will maintain your namespacing found in the asset catalogs.
  3. This additional parameter ensures no matter how many file names you provided in inputs, SwiftGen will maintain separate enumerations to represent each asset catalog.

Build the project, then go back to XCAssets+Generated.swift. You’ll see Assets now contains a new enum named LaunchAssets to represent your folder structure.

Now, it’s time to use this newly generated code to remove any string references to images. Open DrinksListView.swift. You’ll see Image("milkshake") within the toolbar items added on the view. Replace the line with the following:

Image(Asset.Assets.milkshake.name)

Here, you’ve referenced the image name for milkshake. As of now, SwiftGen doesn’t support working directly with SwiftUI. You’ll learn how to add this yourself later. For now, you can still use what comes out of the box to load the image asset without referencing the string directly.