8 tips to speed up your Swift build and compile times in Xcode

Swift is an efficicient language to write but if you’re not careful you can encounter excruciating build and compile times

Optimise your Xcode setup along with some code changes and you can bring your Swift development out of the slow lane

There are many different reasons to why Swift build and compile times can take a significant amount of time. The most prominent and common reason is due to type inference. Essentially, the Swift compiler is particularly slow when parsing and compiling simple Dictionary & Array literals due to expensive type checking procedures.

Unfortunately there are occasions where slow compile times are unavoidable, but the good news is, there are some tools and settings changes you can utilise to speed up your Swift compile and build times.

1) Displaying build times in Xcode

First things first, we need to measure your compile times. It’s important to measure to see that the changes suggested in this article are actually having the deisred affect.

You can enable a timer right within Xcode’s UI. This timer is not visible by default but if you run the following in the command line a time will be displayed each time you build your app.

defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES

After you have enabled the timer, you will see the time it takes to compile your app in the build status bar in Xcode.

The Xcode build status bar after enabling the compile timer

Each time you want to measure the build time of your app, it is recomended that you clean your project (including the build folder ⌘+⌥+K) and delete your app’s derived data. You can do so from the command line with the following command.

rm -rf ~/Library/Developer/Xcode/DerivedData

2) Identify code that compiles slowly

Xcode has inbuilt features that allow you to identify functions and expressions that are causing longer compile times. You can specify a compile time limit and identify areas in your codebase that exceed this limit.

Open up your project’s build settings and add the following flags to your Other Swift Flags.

  • -Xfrontend -warn-long-function-bodies=100
  • -Xfrontend -warn-long-expression-type-checking=100

The 100 integer represents the compile time limit you place on your functions and expressions. It is measured in milliseconds.

When you compile your code, any functions or expressions that exceed 100ms will be flagged up as warning. This provides you an opportunity to refactor your code and reduce those compile times.

3) Build the active architecture only

Your project should only build the active architecure when your Debug configuration is selected. This setting should be active by default but it’s worth checking just in case.

Navigate to Build Active Architecture Only in your project’s build settings. Ensure that Debug is set to Yes and release is set to No.

Ensure Build Active Architecture Only is set to Yes for your debug configuration

4) Optimise dSYM generation

You can use a dSYM file to make sense of your crash reports. This is particulalry useful when you don’t have the debugger attached. However they take time to produce so it makes sense to only produce them when you don’t have the Xcode debugger attached.

Ensure you set your Debug Information Format to always create dSYM files for your Release builds and for your debug builds that aren’t being run on the simulator. You don’t need them to be created when running on the iOS simulator.

dSYM files should not be produced when running on the iOS simulator but should be produced for all other instances

5) Module optimisation

You can set your build settings so that when you run the compiler it runs one job with all required sources files instead of one job for every source file. This does reduce parallelism but significantly reduces duplicated work hence making your build time faster.

To implement this you add -Onone only in the debug configuration of Other Swift Flags under your build settings. You will also need to set Optimisation Level to Fast, Whole Module Optimization in your debug build settings.

Build settings to optimise your modules in your Swift project

If you use CocoaPods you can optimise all of your dependecies by adding the following to the end of you Podile.

post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.name == 'Debug'
config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-Onone']
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Owholemodule'

6) Third party dependencies

The most common way to handle 3rd-party depencies in iOS projects is to use CocoaPods. It’s simple to use but is not the best option if you care about build times.

One alternative that you can use is Carthage. It is harder to use than CocoaPods but it will improve your build times. Carthage achieves this by only building external dependencies when you add a new one to your project. If you haven’t added a new one, your project won’t need to build all of your external dependencies.

If you want to use Carthage instead of CocoaPods, I recomend you start your journey on their Github page and follow their instructions there.

7) Xcode has a new build system

In Xcode 9 Apple introduced a new build system. At the time of writing, this is just a preview and is not enabled by default. One of the main benefits of the new build system is faster build times.

To use the new build system you can enable it in the File menu and select Workspace Settings (or Project Settings if you’re not using a Workspace).

Enable the new build system in Xcode 9 to speed up your build times

From this menu you will be able to select the new build system and reduce the time it takes to compile your Swift code.

8) Enable concurrency when building

In Xcode 9.2, Apple introudced an experimental feature that allows Xcode to run Swift build tasks in parallel. By default this is not enabled and you will need to switch it on yourself from the command line.

defaults write com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively -bool NO

Some projects will see bigger gains than others (up to 40% in some instances). Another caveat to warn you about is if your machine doesn’t have a lot RAM this may actually slow your builds down. If that is the case you can disable concurrent Swift build tasks with the following command.

defaults delete com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively

If this article has been helpful to you, please help me out and tap that clap button below 👏.

If you need more help, would like to contact me or you’re just interested in what I’m up to, you can follow on Twitter @joshgare.