5 Key Reasons for FPS Drops on iOS and How to Fix Them

5 Key Reasons for FPS Drops on iOS and How to Fix Them

When it comes to mobile performance, Apple sets the bar high. iOS apps are known for their smooth, responsive interfaces and consistent FPS.

As iOS developers, we must align with this philosophy of performance – In this article, we’ll explore simple yet effective strategies for optimizing performance. Let us try to follow this philosophy.

“Apple’s integration of hardware and software allows us to deliver a truly seamless experience. Our focus on optimization ensures that iOS apps perform with consistency and reliability, offering the smoothest possible user interactions.”

Craig Federighi, Senior Vice President of Software Engineering at Apple


1. Offloading Business Logic to a Separate Thread ???

Separate Thread

Why: When execute heavy business logic on the main thread, it directly competes for resources with UI rendering. This can cause frame drops, lags, or unresponsiveness, especially when complex calculations are involved. Remember: we're not fighting for "zero to fully loaded" time no matter what – users would rather notice FPS drop than 0.00001 sec penalty for thread switching.

Solution: Offloading tasks such as network calls, data processing, or any heavy computation to a background thread ensures the main thread remains free to handle user interactions smoothly. In Redux or MVVM architectures, separate the business logic from UI-related tasks so that UI updates only happen when necessary.

NIT: whenever you particularly hate your users and want to make them suffer, just place heavy logic somewhere inside viewDidLoad.

This method is often misunderstood as the perfect place to handle initial setup tasks, but it’s really not the best choice for anything that could block the UI. viewDidLoad is called as soon as the view controller’s view is loaded into memory, which means it runs synchronously on the main thread.

Solution: Move heavy logic out of this method or If the task is necessary for the view to be fully functional, consider performing it asynchronously, preferably on a background thread.


2. Efficient UI Updates with setNeedsLayout ?????

Efficient UI Updates

Why: Directly updating layout elements can disrupt the render loop. UIKit handles re-renders effectively if you let it decide when - unnecessary re-renders, can degrade performance. Especially in Redux-like systems with frequent updates, we don't actually have to react on every single new state - the screen won't be able to display it anyways, so...

Solution: When properties change, instead of immediately adjusting the layout, let UIKit handle re-layoutcall: setNeedsLayout prompts UIKit to adjust only when ready. This notifies the system that a layout update is required, but UIKit will decide the best time to apply it.?Override viewWillLayoutSubviews for layout adjustments.


3. Lazy Loading for Large Datasets ????

Lazy calculations

Why: Loading and processing large data sets all at once can freeze the UI, especially if you’re mapping and displaying complex structures. A lot of processing time. But what if we don't calculate thousand items sequentially all an once?

Solution: Implement lazy loading to load and process data incrementally as it’s needed. This minimizes the peak load by spreading it out across timeline -> keeps the app responsive. UITableView and UICollectionView provide mechanisms to lazily load data as cells are about to appear. Also, avoid pre-calculating and caching sizes unless absolutely necessary since AutoLayout can handle most layout adjustments efficiently.


4. Profile Your App with Instruments ????

Profiling

Why: Identifying performance bottlenecks is essential for optimizing your app. If you’re unsure where your app is underperforming, Xcode Instruments is the tool to help you locate areas of concern, like CPU-heavy tasks, slow network calls, or rendering issues.

Solution: Use Instruments to analyze your app’s performance and pinpoint the source of slowdowns. The CPU Profiler helps you monitor how much time each function takes, while the SwiftUI Profiler can highlight specific issues related to SwiftUI rendering.


5. Avoid Overengineering ????

KIS

Why: Premature optimization can lead to unnecessary complexity. Trying to solve performance issues before they arise often results in bloated code and overcomplicated architectures that may not provide any significant improvements.

Solution: Profile your app first to identify actual bottlenecks. Focus on optimizing the areas that affect performance the most, and keep things simple until performance issues are evident. Often, minor adjustments or even using built-in framework optimizations (like AutoLayout or Grand Central Dispatch) can yield more significant improvements than complex solutions.


I hope, these techniques will make a significant impact on your app’s responsiveness and efficiency.

Don’t forget, performance optimization is an ongoing process – continue monitoring, testing, and refining your approach.

Thank you for reading! Let’s keep optimizing!

要查看或添加评论,请登录

Daniel Lisovoy的更多文章

社区洞察

其他会员也浏览了