Part1: Migration from UIKit to SwiftUI

Optimizing SwiftUI List Performance with UIViewControllerRepresentable

Karthik
3 min readMay 18, 2023

If you’re new to SwiftUI and Core Data, it’s highly recommended to familiarize yourself with these technologies before diving in.

  • SwiftUI — Declarative UI framework for building native apps.
  • CoreData — Persistence framework for managing data storage.
  • FetchedResultsController — Efficient data-fetching and results-tracking in Core Data

Migrating our app from UIKit to SwiftUI with the latest tech stacks has presented us with a range of challenges. Initially, we opted to use the SwiftUI List API for populating the Contacts in our list. However, we encountered some challenges along the way.

Please find the latest tech stack here

SwiftUI Diffable Architecture

As our app grew, managing a large number of data became a challenge. With an average of 10,000 contacts per account, rendering the contact list efficiently became crucial for a smooth user experience.

  • Loading a large dataset directly into SwiftUI List with diffable data proved to be inefficient.
  • Though we use @NSFetchReusults with a batchSize of 20, SwiftUI’s diffable data architecture requires loading all the contacts into memory, leading to excessive memory usage and slow rendering times.

After conducting some quick research, we came across the UIViewControllerRepresentable API, which proved to be a valuable solution for our needs.

UIViewControllerRepresentable

UIViewControllerRepresentable is a powerful SwiftUI feature that allows us to bridge UIKit components with SwiftUI. By wrapping a UITableViewController which holds FetchedResultController into SwiftUI, we could able to bring up our desired solution.

UIHostingController

UIHostingController is a class provided by SwiftUI that allows you to embed a SwiftUI view into an existing UIKit-based user interface (Inverse of UIViewControllerRepresentable). In our case, Lists Rows are built with SwiftUI and injected in UITableViewController via Content closure. By utilizing UIHostingController, we can gradually introduce SwiftUI views into our UIKit app, allowing you to take advantage of SwiftUI’s modern approach to UI development while maintaining compatibility with existing UIKit components and functionality.

The Solution

To overcome the performance limitations of SwiftUI List,

  • We created a custom UIViewControllerRepresentable that encapsulates a UITableViewController and uses a FetchedResultsController.
  • The FetchedResultsController efficiently fetches the contacts from Core Data in batches (in our case 20), allowing us to load and display the data incrementally as needed.
  • To integrate SwiftUI views into UITableView, we utilized UIHostingController to inject the SwiftUI view into each table cell during the loading process.
  • Loading the data in batches significantly reduced memory usage and eliminated the delays caused by loading all contacts upfront.
  • The user interface became more responsive, enabling smoother scrolling and faster search results.

Example

Here’s an example of how we implemented FetchedResultsTableViewControllerWrapper which holds UITableViewController and uses NSFetchedResultsController for data handling.

Final Thoughts

  • When working with large datasets in SwiftUI, it’s essential to consider performance optimizations.
  • By leveraging UIViewControllerRepresentable, we were able to optimize the rendering of our contact list by loading the data in batches.
  • With the adoption of UIViewControllerRepresentable, our contact list now allows us to efficiently handle thousands of contacts while maintaining a responsive and delightful user experience.

its worth considering that, Under the hood SwiftUI presented several other challenges, such as issues with onAppear and State not being triggered etc

In the upcoming parts, I will discuss additional challenges and implications I encountered during the migration process.

--

--