Swift Compile Time Tuneup
Last modified on Wed 18 Oct 2023

As our Swift projects were getting bigger, we noticed that the compile time was way above what one would call acceptable. We're talking ~25 min for a clean build.

After some analysis, we realized that there are two major groups of problems—one was Cocoapods and the other was Swift syntax.

Below, you can find some issues and how to resolve them. Also, this isn't a silver bullet, so the best way is to do it gradually and measure intermediate states.

Common issues

Complex expressions, for example:

Bad

let x = ["A", nil, "B", nil, "C"].flatMap{$0}.reduce("", +)

Good

let x: String = ["A", nil, "B", nil,"C"]
    .flatMap { letter -> String? in
        return letter
    }
    .reduce("") { (accumulator, nextItem) -> String in
        return accumulator + nextItem
    }

Concatenation of strings:

Bad

let greeting1 = "Hello, \(firstName) \(lastName)!"
let greeting2 = "Hello, " + firstName + " " + lastName + "!"

Good

let greeting = String(format: "Hello, %@ %@!", firstName, lastName)

Literal array build

Bad

let x = [
    CellItem(name: "A", count: 23, selected: false, actionHandler: {}),
    CellItem(name: "B", count: 12, selected: true, actionHandler: {}),
    CellItem(name: "C", count: 15, selected: true, actionHandler: {}),
    CellItem(name: "D", count: 44, selected: false, actionHandler: {}),
]

Good

var x = [CellItem]()
x.append(CellItem(name: "A", count: 23, selected: false, actionHandler: {}))
x.append(CellItem(name: "B", count: 12, selected: true, actionHandler: {}))
x.append(CellItem(name: "C", count: 15, selected: true, actionHandler: {}))
x.append(CellItem(name: "D", count: 44, selected: false, actionHandler: {}))

The above-mentioned problems may or may not affect your build time. The only way to be sure of this is to actually measure how long does it take for each method call to compile. If you wonder how to do it, scroll to the bottom. ;)

Cocoapods

post_install do |installer|
  puts "********** PODS POST INSTALLATION HOOK **********"
  puts "Updating **BUILD SETTINGS** key **DEBUG_INFORMATION_FORMAT** for **ALL PODS** to allow faster build time by changing **DWARF with dSYM** to **DWARF** when in **DEBUG** ... "
  installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
      if config.name =~ /Debug/
          # This adds the flag to the Pods.xcodeproj itself at the most local level (basically per **Pod**)
          config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf';
      end
    end
  end
end

Global project compile time

$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

Compile time per method call

iOS methods compile time