Just to follow up on this (as it's still an issue in macOS 15.4), based on your feedback, the following should be equivalent in performance (but they're not):
// 1. the 'fast' version
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
fetchRequest: Item.myFetchRequest(),
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
Text("\(item.itemNumber ?? "None")")
}
}
}
}
}
// 2. The 'slow' version
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
fetchRequest: Item.myFetchRequest(),
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
ContentItemView(item: item)
//Text("\(item.itemNumber ?? "None")")
}
}
}
}
}
// extracted subview
struct ContentItemView: View {
let item: Item
var body: some View {
Text("\(item.itemNumber ?? "None")")
}
}
If you add 5k rows here, and try to drag the window scrubber up and down to scroll through the list, you can see the performance problems in the 2nd version. The number of subviews in each row are equal in both implementations.
Your explanation makes sense for iOS but not for macOS, where there's some performance problem under the hood.