Quick start, or How to speed up the launch of iOS programs / Habr

Quick start, or How to speed up the launch of iOS programs / Habr

Hello everybody! My name is Firuza, I am an iOS developer at SimbirSoft. In this article, we will try to figure out how to speed up the launch of the program, namely:

The article will be useful for iOS developers of any level who want to improve the performance of their applications.

High performance and quick response to user actions is an important condition for all mobile applications. According to Apple’s guidelines, a startup time of less than 400 milliseconds is considered acceptable. If the startup takes 20 seconds or more, the system will close the program.

What happens when a user clicks on an app icon?

Launching a program is a process that involves several stages, which the iOS system performs automatically. At this point, UIKit activates the delegate methods to prepare the app for user interaction and perform all the tasks necessary for it to function. Let’s take a look at these stages:

  1. Launch the application: the user clicks on the application icon.

  2. Process creation: The iOS operating system creates an application process.

  3. The system executes the main() function.

The main() function is the entry point for the program, initializes the beginning of the program’s life cycle, and calls other necessary functions to start the program.

  1. The main() function calls UIApplicationMain(_:_:_:_:)which creates an instance of UIApplication and an application delegate, and establishes a relationship between UIKit objects and the application.

  1. UIKit loads the storyboard if it is used.

  2. UIKit calls the method application(_:willFinishLaunchingWithOptions:) in AppDelegate.

  3. UIKit performs state recovery, which causes additional methods in the application delegate and view controllers to execute.

  4. UIKit calls the method application(_:didFinishLaunchingWithOptions:) in the program delegate, which means that the program is ready to run.

  5. After the application is initialized and the delegate methods are called, a runloop is started that handles events and updates the user interface.

Stages of launching the program in the form of a diagram:

After the application is launched, the system uses AppDelegate or SceneDelegate to display the user interface and manage its lifecycle.

How to collect relevant metrics of launch speed and app responsiveness?

With the introduction of iOS 15 pre-warming, the main() function can be called before the user touches the application icon, which initiates the initial launch sequence, but pauses before calling the UIApplicationMain function. In this way, iOS can create and cache any low-level structures that are required to run fully.

Using timers to measure program startup times results in inflated values ​​because the pause in the startup sequence that occurs during pre-warming is not taken into account.

You can collect up-to-date launch speed and responsiveness metrics for your iOS app using various tools and methods described below:

  1. Using Xcode tools

Xcode Organizer used to view startup time metrics, UI responsiveness, memory usage and power consumption, and so on. The tool allows you to group measurements by device models, app versions, and user percentile.

Xcode Organizer helps you find out if you’ve made performance optimizations.

To open Xcode Organizer, select “Window” -> “Organizer”.

The screenshot below shows the analysis diagram of the application launch speed:

Missing data in Xcode Organizer may be because thresholds are not published. The data will be available if several thousand users use each version of the program. It should also be published on TestFligh or AppStore.

Tool App Launch designed to measure program startup time. It provides detailed information about the time taken to start the program and its initialization process.

To use the tool, you need to select Xcode -> Open Developer Tool – Instruments – App Launch and click the Record button (red button in the upper left corner). When the program starts, press the “Stop” button to end the recording. After that, the results of the program launch time analysis will be available.

2. MetricKit – this framework from Apple, which provides an API for collecting and analyzing performance metrics of iOS applications. It is included in the iOS standard libraries and is available starting with iOS 13. Metrics can be presented in the form of histograms, which capture the frequency of values ​​observed throughout the day.

MXAppLaunchMetric is a MetricKit object that provides information about the launch of an application: launch time, initialization duration, and other performance-related parameters.

The system sends performance reports for the previous 24 hours once a day and immediately in iOS 15 and later versions.

Note: MetricKit only works on a real iOS device and is not compatible with the simulator.

To use MetricKit, you need to register MetricKit in the MXMetricManager object, extend AppDelegate with the MXMetricManagerSubscriber protocol, and implement the didReceive(_:).

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MXMetricManager.shared.add(self)
    return true
}
extension AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payloads: [MXMetricPayload]) {}
}

MXMetricManager subscribers receive an array of MXMetricPayload objects containing all metrics. By calling the method jsonRepresentation() you can get data in json format from the MXMetricPayload object, and use it for further analysis, for example, transfer it to the server.

The MXMetricPayload object contains a property applicationLaunchMetrics of type MXAppLaunchMetric, which provides app launch and resume metrics.

An object of type MXAppLaunchMetric has the following properties:

  • histogrammedTimeToFirstDraw – a histogram of the time intervals spent on starting the program.

  • HistogrammedApplicationResumeTime – a histogram of the time intervals spent on resuming the application from the background mode.

  • histogrammedOptimizedTimeToFirstDraw (from iOS 15.2) – a histogram of time intervals associated with preliminary warm-up of the program

A data dump related to MXAppLaunchMetric looks like this:

bucketStart is the start value of the interval, bucketEnd is the end value of the interval, and bucketCount is the number of observed samples falling into the bucket.

The scalar value, which is the average value, is calculated according to the following formula:

What tactics should be used to accelerate launch and launch responsiveness?

Accelerating the start and increasing the responsiveness of the program are important aspects of improving the user experience. Here are some tactics you can use to achieve this goal:

  1. Image optimization:

Large image files can significantly slow down the program. To speed up user interface loading, you can use image compression to reduce their size without sacrificing quality.

For image compression without loss of quality, you can consider the HEIF format.

HEIF (High Efficiency Image Format) is a modern image file format designed to efficiently compress images with minimal quality loss. The advantage of this format is the small file size.

Also, in the asset catalog, you can adjust the compression for each image separately or for the entire group of images at once.

  • Lossless – lossless compression, the size does not change.

  • Automatic – automatic lossy compression.

  • GPU Smallest Size – lossy compression, smallest image size.

  • GPU Best Quality – lossy compression with the best image quality.

  1. Preload data:

If the application depends on remote data, it should be downloaded whenever possible.

  1. Reducing the complexity of the interface:

Simplifying the start screen by reducing the number of interface elements and simplifying the hierarchy of views can significantly speed up application loading and improve the application experience.

Also, reducing the complexity of the animation and using simpler effects will help speed up the loading and start of the program.

  1. Caching:

Using caching to temporarily store frequently used data and resources to reduce load times and increase application responsiveness.

For example, a news feed application that, when launched, downloads a list of news from the server. You can cache downloaded news locally on the device, for example, in a local database. On subsequent program launches, check for cached data and, if available, use it to display on the main screen. Thus, the user gets quick access to the news feed, even in the absence of an Internet connection or with a low data download speed.

  1. Optimization of dependencies:

Static libraries are linked to the program at compile time. When the program is compiled, the required code from the static library is embedded into the resulting binary file.

Dynamic libraries are separate binary files that are linked into a program at runtime. These libraries are not included directly in the application binary, but are loaded into memory as needed.

If when connecting dependencies through the CocoaPods manager, write in the Podfile:

use_frameworks!:linkage => :static

Then all dependencies will be included in the program statically at compile time instead of dynamically at runtime. This can help to speed up the process of starting the program, since all the necessary libraries will already be built into the executable file. However, this can also increase the size of the application.

The speed of launching the program when connecting dependencies dynamically (2.60 s):

Program startup speed when dependencies are connected statically (543.91 ms):

Swift Package Manager (SPM) includes static dependencies by default.

  1. Performance analysis:

Using performance analysis tools to identify bottlenecks and optimize application performance.

  1. Code Optimization:

Optimizing algorithms and data structures to improve performance.

Applying these tactics will help improve the startup speed and responsiveness of the application, which will make the user experience more pleasant and efficient.

Conclusion

In this article, we looked at the process of launching an iOS application, ways to collect relevant metrics, and tactics to accelerate the launch. Understanding this information will help iOS developers improve the user experience by making app launches faster and more responsive.

Thank you for attention!

We also publish more useful materials for mobile developers on our social networks – VK and Telegram.

Related posts