What are your options when you're an iOS developer, and the project you're working on is building slowly?
One option would be to watch youtube videos while it's building, but we all know how much that hurts our productivity. Another option would be to buy better hardware, like one of those new Macs with the M1 chip.
However, as engineers, we know that scalability doesn't just come from more power. It also comes from software optimizations and efficiency, so let's see what we can do on this side for our slow iOS builds.
The long (but detailed) way:
In Xcode, go to Product -> Perform Action -> Build with Timing Summary. This will start a build that gathers information about each step and shows a total amount in seconds at the end.
For the summary, open the Report Navigator, the last tab from the left-side menu in Xcode. It should look like this:
The quick way:
In a Terminal window, type the following command: defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES
The next time you build an iOS project, it will show you the time spent on it, just like this:
You can revert this setting with the same command by writing NO instead of YES.
Let's start with a few settings at the project level that can impact your build times.
Go to File -> Workspace Settings, and make sure that "New Build System" is selected instead of "Legacy Build System"; It should be by default like that for new projects, but just in case.
Next, select your target and go to the Build Settings tab. You'll have here a few things to configure. The first one: search for "Build Active Architecture" and set it to Yes for Debug and to No for Release. In Debug mode, you only need to build for the simulator or device you're using at that time, not for all of them (like in Release mode).
The second one: search for Optimization level, which can be set to: No Optimization, Optimize for Speed, and Optimize for Size. If you don't need to debug right away, set Debug to Optimize for Speed. However, you'll usually need to leave it on No Optimization so you can have breakpoints and inspect variables.
Also, make sure that the compilation mode is set to "Incremental" instead of "Whole Module" so Xcode won't rebuild the entire project every time. Instead, it will only build your changed files.
After you set the optimal settings for your project, it's time to move to code analysis. Inspecting and improving your functions and calculations is crucial and can have a significant impact on build times.
How can you inspect every function and expression? There are a couple of flags that you can set at the target level, along with maximum times in milliseconds. After that, you'll get warnings in the code for each function or expression that exceed those times. Go to Build Settings -> Other Swift Flags, and add the following:
-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=50
In this way, any function that takes more than 100ms to type check will get a warning. Same for expressions that take more than 50ms. You can choose other values, but these are good to start with.
You can take these warnings one by one and try to improve them, but there's one thing you can do to take it to the next level — having a summary of the number of occurrences for each such function. Fortunately, there's an open-source tool that can help you with that. Here’s a link to the code.
The installation instructions are on the repository, and you also need to add this new flag to the Swift Flags section: -Xfrontend -debug-time-function-bodies. After that, you just build your project, and this tool will take the build summary from Derived Data. Here's what it looks like:
Using this Build Time Analyzer, you can work directly on the most "expensive" parts. Let's see some changes that will improve our example from above.
First of all, avoid complex and compound statements. We can change the following code:
to
and this change alone will improve the build time from 2232ms to 738ms. That's because the type-check time was reduced from 248ms to 82ms, and since this function has nine occurrences, the total build time improved by quite a lot.
Another helpful thing is declaring the types of each variable or constant. If we change this code:
to
this will cut in half the build time for this function. Since it has nine occurrences, we get a total time of 1503ms compared to 3042ms as it was before.
In general, go for an easier to read and clearer syntax, even though it might be slightly longer, but also avoid falling into the other extreme where you have twice as much code as you should. A good example would be the Nil Coalescing Operator, which will increase the build time compared to the "if let" alternative, as you can see below:
52ms vs. 156ms
A similar thing happens for the ternary operator, which is not as easy to parse as the traditional if-else statement. Other examples include using String interpolation instead of concatenation or using array.append(contentsOf: ) instead of array + [new array].
You can ensure a better build time for your iOS projects in multiple ways. Some are related to the general project setup, and others are more specific to the Swift code choices.
All in all, it's important to know how to measure the build times in the first place, to play with those time limits, and then focus on the code parts that have the biggest negative impact on build times, aiming to improve them. Some changes might seem minor, improving times by 1 second, but they add up and can make a nice difference in the long run.
If you found this guide useful, then we recommend you check out our other mobile development articles. Stay curious, and see you next time!
Stay up to date with the tech solutions we build for startups, scale-ups and companies around the world. Read tech trends and news about what we do besides building apps.