Doing a stranger social software recently, this kind of software on the market are more or less the same. In order to make our products more competitive, there are other things we can do as developers besides fulfilling the requirements from product managers:
- Collapse rate optimization
- Optimization of interaction
- Optimization of animation
I attribute the optimization of App startup speed to interactive optimization
Generally, App startup can be divided into cold startup and hot startup
- Before the app is started, its process is not in the system, and the system needs to create a new process to assign it to start, that is, the app is started from the case of being killed
- Warm start
After a cold startup, the app will go back to the background. The process of the user restarting the app while the app process is still in the system, that is, the app is started from suspended. This process does very little
This article mainly discusses the optimization of app cold startup. The slow startup perceived by users actually occurs in the main thread, and there are many reasons for the slow main thread, such as the large file read and write operation on the main thread and the large amount of calculation in the rendering cycle. However, sometimes you will find that even if you take care of the main thread before the first screen is displayed, it will still start more slowly than its competitors.
Generally speaking, the startup time of App refers to the time between the user clicks on the App and the user sees the first interface. In summary, the startup of App mainly includes three stages:
main()
Before function executionmain()
After the function is executed- After rendering the first screen
Before the main() function
Before the main() function is executed, the system does a few things:
- loading
Executable file
The (App.o
Collection of files) - Load the dynamic link library, proceed
rebase
Pointer adjustment sumbind
Symbol binding Objc runtime
Initial processing, includingobjc
Registration of related classes,category
Registration,selector
Uniqueness check, etc- Initialization, including execution
+load()
Methods,attribute((constructor))
Modifies function calls to create C++ static global variables
Responsive, things that can be done at this stage for starting speed optimization include:
Reduce dynamic library loading
Each library has its own dependencies. Apple officially recommends using fewer dynamic libraries and merging multiple dynamic libraries as much as possible when the number of dynamic libraries in use is large. In terms of numbers, Apple can merge up to six non-system dynamic libraries into one- Reduce classes or methods that will not be used after loading starts
+load()
Methods can be executed after the first screen rendering is complete, or used+initialize
Method substitution. Because, in a+load()
In the method, running the run-time method replacement operation costs 4 milliseconds. Don’t underestimate the 4 milliseconds+load()
Methods have an increasing impact on startup speed- control
C++
The number of global variables
After the main() function executes
The stage after the execution of main(), which is when the main() function is executed, To the appDelegate (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (launchOptions NSDictionary *) {} method in the first screen rendering related method to complete the home page business code is to be executed at this stage, that is, before the first screen rendering, mainly including:
- Initialize the read and write operations of the configuration file on the first screen
- Read big data from the first screen list
- A lot of calculations for the first screen rendering, etc
A lot of times, we put all the initialization work (such as various SDK initializations) into this phase, resulting in the rendering finishing later. A more optimized development approach should sort out the necessary initialization functions for the first screen rendering, the necessary initialization functions for App startup, and the necessary initialization functions only when the corresponding functions are used. Once you’ve combed through the process, put these initializations into the appropriate stages.
After the first screen is displayed
In this stage after the completion of the first screen rendering, the main tasks are initialization of other business service modules other than the first screen, registration of listening, reading of configuration files, etc. From a function point of view, This stage means by (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (launchOptions NSDictionary *) All execution methods in the {} method scope after the first screen rendering. In a nutshell, this phase is from the time the rendering is done, To (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (launchOptions NSDictionary *) The {} method ends when its scope ends.
At this stage, users can already see the home page information of the App, so optimization takes the last priority. However, methods that block the main thread need to be dealt with first, or they will interfere with the user’s subsequent interactions.
After understanding the work that needs to be completed in the App startup stage, we can optimize the startup speed with a definite aim. These optimizations include both functional-level and method-level optimizations
Startup optimization at the function level
Function-level startup optimization starts at the stage after the main() function is executed
The optimization idea is as follows: after the main() function is executed, only the services related to the first screen are processed before the first screen rendering is completed, and the initialization, listening registration and configuration file reading of other non-first screen services are done after the first screen rendering is completed
Start optimization at the method level
After the function-level startup optimization, that is, after the functions required by the first-screen business are delayed, the time between the user clicking the App and seeing the first screen will be greatly reduced, thus achieving the purpose of optimizing the App startup speed.
After that, what we need to do further is to insist on what time-consuming methods are in the main thread before the first screen rendering is completed, and to delay or asynchronously execute unnecessary time-consuming methods. Typically, the longer methods occur in the context of computing large amounts of data, in the form of loading, editing, and storing resources such as images and files
Monitor App startup speed
- Periodically grab the method call stack on the main thread and calculate the time of each method in a period of time. In the Xcode tool
Time Profile
That’s the way it works - right
objc_msgSend
methodshook
To understand the execution time of all methods
Hook method means to change the method you specify to another method when the original method is executed, or execute the method you specify before and after the original method is executed, in order to master and change the purpose of the specified method.
The hook objc_msgSend approach has the advantage of being very precise, but the disadvantage is that it only works with Objective-C methods. For C methods and blocks, hooks can be achieved using libffi’s ffi_call. The disadvantage is the high threshold of writing and maintaining related tools
In summary, you are advised to use the Hool objc_msgSend method to check the execution time of the startup method if the accuracy of the check result is high