Improving iOS App Performance — Tips and Tricks

Performance plays a key role in the success of any mobile app. Even the most beautifully designed app can frustrate users if it feels slow or unresponsive. Users are unlikely to stay engaged with a product that doesn’t meet their expectations.

As a developer, it’s essential to focus on optimizing the app’s performance to provide a smooth and satisfying experience. Here are some practical steps you can take to enhance your app's performance:


Measure performance: measure, create baseline, measure again

You cannot create high-performance apps without measuring your performance first. You can use Xcode->Instruments->Profiler to see how your app is performing. Creating a baseline and fine-tuning your code to match the baseline would help.

List of options in XCode->Instruments


Decrease Overall Memory Use

Reducing the amount of runtime memory your app uses directly improves its responsiveness. Here are a few things you can do:

Analysing heap memory using Instruments

  • Use CGImageSource for better image handling.
  • Maintain separate image sizes on the server for different use cases.
  • Show low-resolution thumbnails when high-quality images aren't needed.
  • Use the asset catalog to provide images optimized for the device.
  • Choose vector images for scalable and smaller-sized graphics.
  • Use the On-Demand Resources feature to download files only when needed.
  • Load only visible views and the bare minimum data needed at a time.
  • Prefetch and cache images to load them faster.
  • Keep the navigation stack small for smoother performance.
  • Reduce using ‘transparent’ views in your app. The CPU needs to go to extra effort to render them.
  • Avoid drawing shapes like rectangles or circles; use views instead.


Optimizing CPU Usage

Main thread usage as shown in Instruments->Profiler

To optimize your CPU usage, you can do the following.

Minimize Notifications, KVO, and Timers

  • Notifications, Key-Value Observing (KVO), and Timers can constantly poll the CPU, affecting app performance. Use these features sparingly and only when necessary.
  • You can also consider avoiding too much use of dictionaries, as hashing in dictionaries burns CPU time. Consider creating custom models using structs.


Manage Power-Hungry Features

Features like Camera, ARKit, and Location Services consume significant CPU resources. Here's how to optimize them:

  • Location Services: Use low accuracy settings when high precision isn’t required — low accuracy equals lower power usage.
  • Avoid starting startUpdatingLocation() until location services are needed. Stop location updates (stopUpdatingLocation()) immediately after use to prevent "location leaking."
  • Camera and ARKit: Reduce frames per second (FPS) if high FPS is not required.


Avoid main thread blocking and thread explosions

While downloading an image from the web it is a common practice to use a background thread, and once the download is completed, the UI operation on the main thread is called. e.g:

func downloadImage(from url: URL) {
    getData(from: url) { data, response, error in
        guard let data = data, error == nil else { return }
        // always update the UI from the main thread
        DispatchQueue.main.async() { [weak self] in
            self?.imageView.image = UIImage(data: data)
        }
    }
}        

This approach works fine when the number of images is small. However, when the number of images is large, this can create a problem called ‘thread explosion’ where too many background threads are created and the CPU gets overloaded. To avoid this you can use a dedicated serial async queue for all the imaged download operations. Alternatively, you can use OperationQueues, and make sure to cancel any downloads that started but are not required for display.


Optimize Networking Operations

  • Do less, do it later, do it efficiently: Delay network operations until results are genuinely needed. Avoid calling multiple APIs during app launch.
  • Indexing: For displaying data in a table or collection view, make sure that the API supports indexing so that it returns data page-wise and we only fetch what is going to be shown to the user.
  • Share Results: Reuse previously fetched data instead of making redundant requests.
  • Prefetching: Implement prefetching delegates (e.g., for collection views) to improve performance and user experience.
  • Caching: Cache session data, especially media like thumbnails and images, to reduce redundant downloads.
  • Defer Heavy Tasks till on Wifi: Delay resource-intensive tasks like large media downloads until the device is plugged in and connected to WiFi.
  • Load Smartly: Load only visible views and the bare minimum data required. Use lazy loading to fetch content as needed.

These practices ensure efficient CPU utilization, smoother performance, and a better user experience.


Manage disk operations efficiently:

Core Data & Storage Optimization: For efficient use of Core Data, you can:

  • Use batching
  • Use faulting
  • Use fetch limits
  • Use predicates
  • Use background context for heavy operations

Reduce Disk Writes: File write operations are CPU-intensive. Avoid multiple disk operations by delaying and batching them to improve performance.


If you found this article helpful, I’d love to hear your thoughts! Feel free to share your feedback. If you’d like to show appreciation or support my work, you can buy me a coffee using this link: paypal.me/sachindraPal. 😊

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics