Analysis tool: The Timer Profiler of the Instrument comes with Xcode.
Test equipment:
- IPhone6 iOS 12.4.8, this device is relatively old, the startup speed of our App on this device is very slow, so the effect is obvious.
- Iphone7 iOS 13.4
- IPhone11 iOS 14.0.1
Test method: Click record to start the App and click Stop at the end of the App startup page to observe the time consuming of the main thread.
Test startup result
IPhone6 iOS 12.4.8
Start is 5.71s and _DYLD_START is 327ms. The second load of dyLD is directly loaded from the cache.
Iphone7 iOS 13.4
The mainline runs in 1.57 seconds, with 1.50 seconds for start and 70ms for _DYLD_START
IPhone11 iOS 14.0.1
The main thread takes 754ms, 642ms for start and 111ms for _dyLD_START
The longest time we saw was in iOS12 on iphone6. The 6 second startup time was unacceptable. Let’s take a look at the methods in main that took up most of the time.
First we select the Call Tree button in the lower left and hide system methods so that we can see our own methods.
After hiding the system, only the list of methods and the elapsed time of our code are left, but it is found that these methods are addresses, not the actual method names after parsing, as shown in the figure:
Notice here that you need DSYM to resolve to the corresponding method name, you need to modify the project buildSetting, and in the corresponding build mode, selectDWARF with DYSM File
:
If there is a component method in the startup process, the component is integrated through Cocoapod and needs to be set on the corresponding component as well, by traversing the global Settings:
post_install do |installer|
installer.pod_target_subprojects.flat_map { |p| p.targets }.each do |t|
t.build_configurations.each do |config|
Set debug mode, other modes are similar
config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
end
end
end
Copy the code
After setting it, you need to perform itpod install
Run the project to the phone again and check the code Time using the Time Profiler:
As you can see, there are three object in the start-up process time consuming method, start HBHRouterManager. RegisgerRootVC (vc) method takes 5.71 seconds, we project routing registration processing, the method is called the global list of classes and corresponding Scheme of link mapping table, So it takes time. So we need to optimize our time-consuming methods as needed, either by tuning them or by delaying the call without blocking the main thread startup process. Especially the Appdelegate application (_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool do not block the main thread by doing time-consuming work before returning. Try to sleep(10) before this method returns, and your App will definitely start in 10 seconds or more.
Let’s deal with this time-consuming method in a simple way:
// The child thread executes the registered routing method asynchronously, without blocking the main thread startup process
DispatchQueue.global().async {
HBHRouterManager.shared.regisgerRootVC(vc: rootViewController)
}
Copy the code
Run again to see the startup time:
It can be seen that the call time of main and start is directly reduced to 436ms, and the startup time of App on iPhone6 is reduced from about 6 seconds to 739ms. Take a look at the remaining two machines:
Iphone7 iOS 13.4
The main thread takes a total of 339ms seconds, with start consuming 256ms and _dyLD_START consuming 72ms
IPhone11 iOS 14.0.1
The mainline runs 146ms, with 38ms for start and 108ms for _dyLD_START
In this way, other time-consuming methods can be tuned by corresponding optimization schemes to achieve the simplest optimization of start-up speed.
This is just a brief introduction to the optimization of the time-consuming method when the main thread is started and executed. Different startup scenarios have different influences on the time-consuming of the App. Apple gives us several startup scenarios:
- Restart the phone and start the App for the first time.
- Force the App to exit and then start.
- Open other apps, and then launch your App.
- Use a very large App (for example, one that can input with many graphical resources or live cameras), and then launch your application.
It also lists other factors that affect startup speed:
-
The number of App dynamic library directly affects the loading time of DYLD.
-
Static library initialization:
C++
Static constructors.- In a class or classification
+load
Methods. - Tagged with clang attributes
__attribute__((constructor))
Methods. - Linked to any function in the App or Framework
__DATA
,__mod_init_func
.
As for the online version of the App Launch Time statistics, Apple also provides a tool to directly view the Launch Time of the unavailable version: Xcode -> Window-> Organizer -> Metrics -> Launch TimeFinally, attached is the official website optimization document:Apple official website to start optimization document