How Huolala Optimized iOS App Startup Speed: Tools, Metrics, and Best Practices
This article details Huolala's systematic approach to improving iOS app startup performance, covering metric definitions, monitoring setup, tool usage, optimization techniques across launch phases, long‑tail handling, anti‑degradation measures, and the resulting performance gains.
Preface
During rapid business growth, the Huolala client app accumulated technical debt, resulting in poor performance compared with leading apps and frequent user complaints about lag and crashes. This article explains the practice of optimizing the app's startup experience.
From a user perspective, key perceivable metrics include:
Installation package size
Launch speed
Stability
Battery consumption
Fluidity
The focus of this post is on the "launch speed" aspect; other metrics will be covered in future series.
Launch‑Related Metric Definitions
Launch can be divided into cold launch (first open or after the app is killed) and hot launch (app already in background). Hot launch bypasses the normal launch flow, so the discussion concentrates on cold launch.
Launch duration = timestamp at launch end – timestamp at launch start
Launch start = process creation time
Launch end = defined as the moment the home page first‑screen rendering completes (iOS viewDidAppear of the root view controller)
Monitoring First
After defining the metrics, a monitoring system for online launch duration was built.
Monitoring consists of two steps:
1. Metric collection and reporting
Core metric: launch duration; device info: OS version, app version, etc.
2. Dashboard design
The dashboard visualizes the distribution of launch durations and compares versions. Based on industry standards, launch times are grouped into intervals: under 3 s, 3‑4 s, 4‑5 s, over 5 s .
Determining Optimization Directions
iOS launch consists of three stages:
Before main() : OS loads the executable, performs linking, then reaches main().
After main() : Execution from main() to the end of AppDelegate 's didFinishLaunchingWithOptions.
After first‑screen rendering : All code executed after the home page appears.
Common optimization ideas for each stage:
Pre‑ main() optimizations
Reduce dynamic library loading; merge libraries when possible.
Avoid loading classes or methods that are not used during launch.
Defer work in +load() to after first‑screen rendering or replace with +initialize().
Post‑ main() optimizations
Avoid I/O on the main thread.
Move third‑party SDK initialization to background threads.
Reduce heavy computations during first‑screen rendering.
After first‑screen rendering Although the user can see the home page, any method that blocks the main thread should still be prioritized for optimization.
The plan follows a "easy‑first, hard‑later" strategy, starting with high‑impact, low‑effort actions in the post‑ main() phase.
Tool Introduction
Effective launch analysis requires lightweight tools:
Tool 1: Xcode DYLD PRINT (measure pre‑main time)
DYLD is the dynamic linker on macOS/iOS. Adding the environment variable DYLD_PRINT_STATISTICS=true to the scheme prints detailed launch timing logs.
Total pre‑main time: 2.1 seconds (100.0%)
dylib loading time: 743.48 ms (34.0%)
rebase/binding time: 163.35 ms (7.4%)
ObjC setup time: 54.74 ms (2.5%)
initializer time: 1.2 seconds (55.9%)
...The log shows that dynamic library loading, rebasing, ObjC setup, and other initializers consume significant time.
Tool 2: Instruments Time Profiler
Time Profiler helps locate slow APIs and answers “where does the time go?”.
Key options:
Separate by Thread : Shows CPU usage per thread.
Invert Call Tree : Displays deepest call first.
Hide System Libraries : Focuses on app code.
Flatten Recursion : Treats recursive calls as a single entry.
Top Functions : Shows total time spent in each function including its callees.
Tool 3: Messier
Messier tracks Objective‑C method calls on arm64 devices, providing fine‑grained timing that Time Profiler may aggregate.
Integration steps include adding messier.framework to the Xcode target, creating a copy phase, and configuring environment variables such as MessierInlineHook, MessierEnableOnAppBoot, and MessierMainThreadMethodsOnly. Note that enabling both inline hook and app‑boot tracing may cause crashes; keep defaults false.
Optimization Practice
Based on the identified directions and Messier data, the main actions were:
1. Asynchronous loading and caching of startup network requests
The app originally performed two serial, blocking requests for global config and AB testing data. Since the data changes infrequently and real‑time requirements are low, the requests were made asynchronous and cached locally.
2. Design a launch‑task manager
All startup tasks were broken into atomic units and classified by dependency, concurrency, and priority. Separate queues execute tasks accordingly. Example categories:
Must run on main thread synchronously (e.g., analytics SDK init, map SDK init, setting root view controller).
Must run on main thread but can be delayed (e.g., payment SDK init).
High‑priority background concurrent tasks (e.g., real‑time logging, crash reporting).
Normal‑priority background tasks (e.g., analytics SDK init).
After these optimizations, the proportion of launches under 3 seconds increased by roughly 13 %, and the average launch time approached 1 second.
3. Long‑tail mitigation for low‑end devices
By comparing detailed function‑level timings on high‑end and low‑end phones, the team identified business‑related APIs that dominate the extra latency on low‑end devices and targeted them for further improvement.
Anti‑Degradation Measures
After achieving a near‑instant launch, safeguards were added to prevent performance regression during rapid iteration:
1. New SDK intake evaluation
Assess necessity, measure initialization cost, and recommend loading strategies (idle‑time, asynchronous, delayed, or main‑thread).
2. Maintain launch‑task manager
Any new task must be scheduled according to dependency and priority.
3. Pre‑release launch‑time testing
The testing team runs automated performance tests on the MTC platform for each version, generating reports on memory, CPU, and launch duration. A deviation larger than 100 ms triggers a failure and requires developer investigation.
Results and Future Plans
1. Achievements
Launch‑time recordings from August 2021 vs. December 2021 show noticeable speedup.
Monitoring data confirms the reduction.
2. Future Roadmap
Configure alert thresholds for launch‑time intervals.
Add Time‑To‑Full‑Display (TTFD) metric alongside the current Time‑To‑Initial‑Display (TTID) to better reflect user perception.
TTFD : Time from app launch to complete rendering of all content (local or network) and readiness for interaction.
TTID : Time to first visual rendering, commonly used as the launch‑time definition.
Optimizing TTID may inadvertently increase TTFD if heavy work is merely deferred; therefore the next step is to monitor and improve TTFD.
Conclusion
The article presented Huolala iOS client’s launch‑optimization practice, covering direction identification, monitoring setup, tool usage, concrete actions, and anti‑degradation strategies. The general principles—start easy, monitor rigorously, and guard against regression—are applicable to most performance‑optimization projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
