问题
I have a List with displays the result of a dynamic FetchRequest.
The code works fine, but having a bigger result set (e.g. 3000), the list is built quite slowly when the dynamic predicate changed.
struct ItemList: View {
@State var startsWith: String = "A"
var body: some View {
NavigationView {
VStack {
TextField("Startswith", text:$startsWith)
FilterRequestList(filter: startsWith)
}
.navigationBarTitle("Tasks CD")
}
}
}
struct FilterRequestList: View {
var fetchRequest: FetchRequest<Item>
init(filter: String) {
if filter == "" {
fetchRequest = FetchRequest<Item>(entity: Item.entity(),
sortDescriptors: [],
predicate: nil)
} else {
fetchRequest = FetchRequest<Item>(entity: Item.entity(),
sortDescriptors: [],
predicate: NSPredicate(format: "title BEGINSWITH %@", filter))
}
}
var body: some View {
VStack {
Text("Count: \(fetchRequest.wrappedValue.count)")
List(fetchRequest.wrappedValue, id: \.self) { item in
Text("\(item.title) ")
}
}
}
}
Any Idea, how to improve that?
Update: What I discovered: The first List is quite fast, but if the startsWith State changes, the reload is very slow. I added
FilterRequestList(filter: startsWith)
.onAppear(perform: { print("appear F") })
.onDisappear(perform: { print("disappear F") })
and discovered, the the FilterRequestList
is not disappearing and reappearing, when the filter changed.
Could that be the problem? How can a recreation be forced?
回答1:
Thanks to Paul Hudson I found the solution for the problem. In "https://www.youtube.com/watch?v=h0SgafWwoh8" he explains it in detail.
You simply have to add the modifier
.id(UUID())
to the list.
The problem was, that swiftUI tries to detect any changes form the old list to the new one to animate the changes. With the modifier the old and the new list for swiftUI are not the same lists (because of the always changing id), so there is no need to detect the changes. Swift can simply create the new list very fast. The only downcast is, that therefore there is no animation.
struct ItemList: View {
@State var startsWith: String = "A"
var body: some View {
NavigationView {
VStack {
TextField("Startswith", text:$startsWith)
FilterRequestList(filter: startsWith)
}
.navigationBarTitle("Tasks CD")
}
}
}
struct FilterRequestList: View {
var fetchRequest: FetchRequest<Item>
init(filter: String) {
if filter == "" {
fetchRequest = FetchRequest<Item>(entity: Item.entity(),
sortDescriptors: [],
predicate: nil)
} else {
fetchRequest = FetchRequest<Item>(entity: Item.entity(),
sortDescriptors: [],
predicate: NSPredicate(format: "title BEGINSWITH %@", filter))
}
}
var body: some View {
VStack {
Text("Count: \(fetchRequest.wrappedValue.count)")
List(fetchRequest.wrappedValue, id: \.self) { item in
Text("\(item.title) ")
}
.id(UUID())
}
}
}
来源:https://stackoverflow.com/questions/59604764/performance-issue-with-swiftui-list