May 11, 2022

Improving iOS App Launch Time

Max Mylashko |

Knowledge

Cliff notes for the curious and non-technical

You clicked on this blog which tells us you are one of two people. A developer looking to increase your impact in the software development life cycle (SDLC) or you’re non-technical but have a thirst for knowledge. Improving iOS app launch time isn’t difficult – it just requires some attention and care.

Have you shouted at your car as it take too long to turn over in the cold; sat in awkward silence with a cashier as you wait for the receipt to print; or, perhaps, stared at the ceiling while you wait for that app you just downloaded to open. These are all the pains of a launch that takes too long.

Before

After

In software development, improving iOS launch time is forgotten more than you may think. After all, it might not be the reason why a user stops using an app. When treated with care, however, details such as iOS launch optimization are important components of creating a remarkable digital experience.

Many agencies are faced with time and budget constraints that make it easy to forget about the small details. We are strong believers in the design thinking process which puts user experience at the forefront of development – no matter what.

What’s a launch and what happens when we launch an app

An iOS ‘launch’ is what happens when you go to open your favourite app. The launch itself is the period of time between pressing the app, and the application actually being open and ready to use. We see this as an interruption to the user’s experience and should be as short as possible.

You might not expect it, but performing a launch is an intense process for your phone. It involves a lot of work from your CPU and memory.

Launches cover a huge part of the application’s codebase, from framework loading to initialization, view creation, and more. Reducing your launch time will help improve the overall system performance and your user’s battery life.

The three types of launches:

Cold Launch

Cold launches occur after a reboot or when your app hasn’t been launched for a very long time. In order to launch an app, we need to bring it from your phone’s disk drive into its memory, startup system-side services that support your app, and then spawn your processes – such as framework loading, app initialization, and view creation. As you may have expected, this can take a bit of time.

Warm Launch

Once a launch has happened once, you’ll experience a warm launch. In this case, your app still needs to be spawned, but your device has already brought the app into memory and started up some of those system-side services. This is a much quicker launch.

Resume

Finally, there’s a resume. This occurs when a user re-enters your app from either the home screen or the app switcher. Because the app has already been launched, this process is very fast.

Measuring Launch Speed

So we’ve talked about what a launch is and the different types, but improving your iOS launch time requires usable measurements to start making improvements.

At any given time, an iOS device is under a variety of different states and conditions which can introduce substantial inconsistencies in a launch. When we’re analyzing and comparing our launch results, it’s critical to ensure that we’re making apples-to-apples comparisons. 

Why is this important? How will you know if you’re making any progress if your launch environments are inconsistent while you make changes? The solution is to ensure a predictable launch by removing inconsistencies, such as networking and background process interferences.

Here are some tips to set up a clean and consistent environment:

Reboot your device

Log out of iCloud

Turn on airplane mode or mark out your network dependencies in code

Use the release version of your application

Conduct measurements with warm launches

Improving iOS App Launch Time

When you’re reviewing your app’s launch both in code and instruments, you should keep these three tips and tricks in mind.

Minimize

Prioritize

Optimize
Minimize Your Work

Defer anything unrelated to generating the first frame. This means deferring things like undisplayed views or pre-warming features that are not yet used. You should also avoid blocking the main thread, either with network I/O, file I/O, or more, as this will affect the launch. Instead, you might consider moving it to a background thread.

Prioritize Your Work

It’s critical to ensure that work is scheduled at the right quality-of-service (QoS) class. A QoS class categorizes work to perform on a DispatchQueue. By specifying the quality of a task, you indicate its importance to your app. When scheduling tasks, the system prioritizes those that have higher service classes.

Because higher priority work is performed more quickly and with more resources than lower priority work, it typically requires more energy than lower priority work. Accurately specifying appropriate QoS classes for the work your app performs ensures that your app is responsive and energy-efficient.

Optimize Your Work

Anything that’s remaining after you’ve minimized and prioritized should be optimized – that means limit and simplify. For example, limit the amount of data that you fetch only to only what is needed during launch or lazily compute any variables and results that you need. When doing this, take a look at your methods and algorithms and see if you can optimize them. This could provide significant improvements by calculating a result differently or using an alternative data structure. Finally, you should cache your resources and complications to simplify the CPU and memory overhead by doing work multiple times unnecessarily.

Walking the walk

Let’s see how we can use the app launch template in Xcode Instruments to understand and improve our app’s launch. One important thing that we should do before we do any performance-related analysis is to select the profile scheme in Xcode.

This will ensure Xcode recompiles your app in release mode, so that you can take the advantages of compiler time optimizations. Once Xcode recompiles your app, it will install it on your device and launch Instruments.

One thing to note here is that as you make incremental changes, you should consistently re-measure and re-profile as you make progress. That way, you can actually understand the exact impact of your incremental changeset.

To get a better understanding of what our users would experience, we can leverage XCTest APIs to measure launch performance within a test. With just a few lines of code, we can actually integrate launch performance tests, or any performance tests, with an XCTest.

At this point XCTest will do one throwaway launch attempt, which cancels out the variance that would come about by cold launches. Then, it will do the specified number of iterations or by default five iterations of launches and measure the time it took.

Don’t let performance be an afterthought.

You should start working on it and think about it at the beginning of every bug fix, re-factor, and feature. It’s incredibly easy to introduce regression, especially a little one like 2 milliseconds. Little issues add up to a big problem, and if you don’t address them immediately, it becomes very hard to find them all. In order to detect regressions, you should be plotting your app’s launch over time and running tests regularly.

Finally, you should be tracking your performance in all phases of development.

This means utilizing the new XCTest app launch measurements on a variety of devices and possibly integrating this with continuous integration. This will ensure that you’re consistently delivering a great app launch to all of your users on all of their devices.

Mission control, we are ready for launch. Hungry for more insights on strengthening your software development life cycle? Check out our recipe for What Makes a Good Bug Report.

Ready to develop your project beyond expectations?

Want to Build a Great Digital Product?

Send this to a friend