SwiftUI List performane

I have a performance issue with List when I have a large amount of data that is replaced. Given the code below, a data set of about 3500 name items are loaded from a fetch request. Depending of the selected gender in the segmented picker these items are filtered and the displayed in the List. When the List first render I have no performance issue with the loading and rendering of items. It scrolls nicely and smoothly through 1700 items. But as soon as I switch gender through the segemented picker it takes about 30-45 seconds to render the List again.


I think this has to do with removing 1700 items and the inserting 1500 items again from the List. Is there a best practice how to reload a large amount of items in SwiftUI? Or can I reset the List before I load it again, since there is no issue initially.


Anyone else having issue same issue?


struct NameList: View {
    
    @ObservedObject fileprivate var global = GlobalSettings()
    
    @FetchRequest(
        entity: Name.entity(),
        sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)]
    ) var names: FetchedResults<Name>
    
    @State var selectedGender = Defaults.gender
    
    var body: some View {
        
        let filtered = names.filter { $0.gender == self.selectedGender }
        
        return NavigationView {
            
            VStack {
                
                Picker("Gender", selection: $global.gender) {

                    Text(Gender.female.rawValue.uppercased())
                        .tag(Gender.female)

                    Text(Gender.male.rawValue.uppercased())
                        .tag(Gender.male)

                    Text(Gender.unisex.rawValue.uppercased())
                        .tag(Gender.unisex)

                }
                .pickerStyle(SegmentedPickerStyle())
                .padding()
                
                List( filtered, id: \.self) { (item: Name) in
                   NameListRow(item: item)
                }
            }
            
        }
        
        .onReceive(Defaults.publisher(for: \.gender)) { (gender) in
            self.selectedGender = gender
        }
        
    }
    
}

Thanks for your info, and I've already watched this video. However, this can only help for the List, right? My problem now is on a Detail List View. How to perfectly fix this issue? Anyone can help?

I know this question was answered a while ago but your problem is having the state value in the top level view and not the subview.

What you want:
  • Top level view - don't reload the List

  • NameListRow - Show or hide based on gender

Solution

Code Block
struct NameList: View {
@ObservedObject fileprivate var global = GlobalSettings()
@FetchRequest(
entity: Name.entity(),
sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)]
) var names: FetchedResults<Name>
var body: some View {
return NavigationView {
VStack {
Picker("Gender", selection: $global.gender) {
Text(Gender.female.rawValue.uppercased())
.tag(Gender.female)
Text(Gender.male.rawValue.uppercased())
.tag(Gender.male)
Text(Gender.unisex.rawValue.uppercased())
.tag(Gender.unisex)
}
.pickerStyle(SegmentedPickerStyle())
.padding()
List( names, id: \.self) { (item: Name) in
NameListRow(item: item)
}
}
}
}
}
struct NameListRow: View {
@State var selectedGender = Defaults.gender
var item: Item
var body: some View {
Group {
if self.selectedGener == item.gender {
content
}
}
.onReceive(Defaults.publisher(for: \.gender)) { (gender) in
self.selectedGender = gender
}
}
var content: some View {
*view logic*
}
}

SwiftUI List performane
 
 
Q