Is there any way to speed up filtering a SwiftUI List when searching?

I'm having a lot of performance issues with SwiftUI Lists and I can't seem to find any solution. Currently, if you have a List with 10_000 items and try to filter it, the app hangs for 1 second at the beginning of filtering, looking at Instruments it seems to be an issue with the underlying UITableView to perform the animations.

Here's a very tiny example to demo the issue:

struct Item: Identifiable, Hashable {
    let title: String
    var id: String { title }
}

@main
struct ListFilteringDemoApp: App {

    private let allItems = (0...10_000).map { _ in Item(title: UUID().uuidString) }

    @State var searchQuery: String = ""

    var filteredItems: [Item] {
        if searchQuery.isEmpty {
            // No filter applied
            return allItems.filter { _ in true }
        } else {
            return allItems.filter { item in
            item.title.localizedCaseInsensitiveContains(searchQuery)
            }
        }
    }

    var body: some Scene {
        WindowGroup {
            NavigationView {
                List(filteredItems) { item in
                    Text(item.title).id(item)
                }
                .navigationTitle("Filtering")
                .searchable(text: $searchQuery, placement: .navigationBarDrawer(displayMode: .always))
            }
        }
    }
}

I know that having 10_000 items in an array is not common. But using Core Data with a @FetchRequest, having 10_000 items is very easy to achieve for the kind of app that I'm building, and the issue is the same.

The issue is present on device (iPhone 12 Pro, iOS 15.1), macOS and iOS Simulator.

I've two questions:

  1. Is there a better way to filter a list while searching?
  2. If the answer is no, is there any way to prevent the animations on a List while being filtered to try to improve the performance?

Thanks!

PS: For Apple folks, I've opened a feedback which includes a sample project to reproduce the issue and a saved Instruments .trace. Number: FB9763003

Does it still lag if you replace item.title.localizedCaseInsensitiveContains(searchQuery) with just item.title.contains(searchQuery)? Does it still lag if you build with optimizations turned on? (Don't leave it for debug after that, just to check if it lags on release builds). The .filter { _ in true } is unnecessary and certainly does not help especially in debug builds. If all that fails, yes you probably can turn off the animations using .animation(nil, value: searchQuery). Your other option would probably be a fast custom string search, something like KMP.

@exCore Yes, it did lag, even when running from the App Store. And you're right, the .filter { _ in true } is uneeded, I just left it there by mistake because my original code was using @FetchRequest to get the data from Core Data instead of in memory, and it's needed in that case. I haven't tried the .animation(nil, value: searchQuery), I will and I'll report back, thanks for the tip.

What did work for me, in case that anyone is reading this, is actually putting an .id(searchQuery) on the List itself. That way, every time that the searchQuery changes, the List is thrown away and recreated to avoid the diffing process.

Thank you @xmollv! Changing the id to qeury instead of UUID() as everybody else suggests helped me and now my list along with searchable works flawlessly!

Is there any way to speed up filtering a SwiftUI List when searching?
 
 
Q