App startup speed is a very important part of user experience, just like the first impression of a person, which determines whether they will continue to communicate. Thus, the startup speed of the App is very important. Of course, in the initial stage of a general project, the optimization of startup speed is not just necessary, because the project is very small at the beginning, but only when the project is large, the startup needs to load a lot of configuration and third-party framework initialization, this time for the startup speed is very sensitive.

This time, I will analyze and express my understanding from the two aspects of App startup process and optimization.

I. Startup of App

Generally we are divided into cold start and hot start, here I briefly introduce the concept of hot and cold start

  • Cold start: When the App is started, that is, when it enters the foreground, the process of its application does not exist in the system. The system needs to create a process for startup, and this optimization is also aimed at this process
  • Hot startup: The process in which the App has been displayed in the foreground after cold startup and is returned to the background from the foreground. At this time, the process is still in the system and has not been destroyed. The user enters the foreground from the background again. We also did less optimization in the process.

After finishing hot and cold startup, we know that the startup speed is actually measured by time. The user perception of slow startup time is actually the main thread is slow, and the main thread is slow for many reasons, such as

  • Read and write operations to large files at startup
  • A lot of calculations at render time
  • other

From the above, we know that the slow startup actually means that the main thread has too many time-consuming tasks, which affects the time of the whole startup process. Our goal is simple, that is, to find out the time-consuming things in the startup process, and deal with them according to the needs, and improve the speed of startup.

And how do we find the time-consuming tasks in startup? Before we do that, we need to understand what the application is doing during startup.

Generally, start-up can be divided into three stages:

  • Before the main() method is executed
  • After the main() method is executed
  • The first screen is rendered

A schematic of the entire rendering process is shown below:



Before the main() method is executed, the system does a few things:

  • Load the executable, the collection of the App’s.o files
  • Load dynamic link library, rebase pointer adjustment and bind symbol
  • Initialization of Ojbc runtime, including registration of OJBC-related classes, classification registration, etc
  • Initialization, including the load +load() method, creating C++ static global variables, etc

This piece of knowledge is relatively deep, we will not expand here in detail, here we can make the following optimization:

  • By reducing the amount of dynamic libraries loaded at startup, Apple itself recommends less use of dynamic libraries and the option to merge dynamic libraries when more are available.
  • Reduce classes or methods that will not be used after loading is started, that is, we need to remove some old code that will not be used in time, and do regular cleaning and maintenance.
  • The +load() method can be used only after the first rendering is completed, or the +initialize() method can be used to replace the content, because in a load() method to replace the method, there is a 4ms delay, if there are many methods, the time is considerable.
  • Control C++ global variables

The main () method performs, we generally refers to the main () began to perform AppDelegate didFinishLaunchingWithOptions method execution is finished.

Usually, the business code for the first screen is also in here. Here we do things like:

  • Read and write configuration files for the first screen initialization
  • Read and write data on the first screen
  • A lot of calculations for the first screen rendering
  • Initialization and loading of the third library

We need to figure out which functions are necessary for home page rendering and which can be loaded on demand when used, and then allocate initialization and loading to each trigger node to evenly distribute the time.

After the completion of the first screen rendering, generally refers to didFinishLaunchingWithOptions method at the end of the scope to the first screen rendering, after the completion of this stage the user can see the home page, but to be stuck the main thread of the way to get rid of or on-demand, we at this stage can complete some tasks at the same time, such as:

  • Initialization of other service modules other than the first screen
  • Monitor registration and configuration of other services

Based on the above analysis of App startup process, we can probably know the optimization points. Next, we will put forward some optimization solutions from the function level and method level.

Feature level startup optimization:

As we all know, in the early stage of the project, the code is relatively easy to control, but in the later stage, the code will become disorderly, all kinds of accumulation, no specification, difficult to maintain and other problems, such as the project I am working on now. This kind of optimization can not be solved by one person, but requires a team to work together to set standards and standardize the documentation.

Here, my optimization idea is as follows: From the execution of main() method to the completion of the first screen rendering, only the first screen related business, including configuration and setting, file reading, initialization of the necessary third-party library; Other business and things unrelated to the first screen are deferred until the first screen is rendered.

Method level startup optimization:

After we do the initialization tasks that are relevant to the first screen delay to render first screen after the completion of the initialization, can start drawing velocity, but it is not enough, we can continue to check, before the completion of the first screen rendering, which exist in the main thread of time-consuming method, unnecessary time consuming method lag or asynchronous execution, The necessary time-consuming methods to do as much as possible algorithm optimization, this part is mainly in the loading, editing, storing images and file resources.

In addition to the image files and other resources mentioned above, the +load() mentioned in the previous point may also affect the startup speed, so we need to use some tools to do a comprehensive and accurate check and monitoring of the function in the startup process.

We can use the official tool Time Profiler provided by Xcode. The advantage of using it is that the cost is low and Xcode itself has perfect support. As the version upgrades, you can enjoy the optimizations it brings. Basically meet the use.

I won’t expand on how to use the Time Profiler here, but there is a fire chart that needs to be explained in more detail later, and a Tutorial with Swift: Getting Started is attached.

Conclusion:

Optimization and monitoring of startup speed is actually a very important process, many products will work on it, such as a treasure, a letter and other large flow products, which is the biggest improvement of user experience.

I put forward my own ideas on startup optimization from two aspects. In a big sense, it is about sorting out the initialized business code and reasonably delaying or asynchronously processing the business code irrelevant to the first screen. From a small point of view, we can use quantitative tools such as Time Profiler to analyze and optimize each method in detail to improve startup speed.