I’m experiencing significant performance and memory management issues in my SwiftUI application when displaying a large number of images using LazyVStack within a ScrollView. The application uses Swift Data to manage and display images.
Here’s the model I’m working with:
@Model
final class Item {
var id: UUID = UUID()
var timestamp: Date = Date.now
var photo: Data = Data()
init(photo: Data = Data(), timestamp: Date = Date.now) {
self.photo = photo
self.timestamp = timestamp
}
}
extension Item: Identifiable {}
- The photo property is used to store images. However, when querying Item objects using Swift Data in a SwiftUI ScrollView, the app crashes if there are more than 100 images in the database.
- Scrolling down through the LazyVStack loads all images into memory leading to the app crashing when memory usage exceeds the device’s limits.
Here’s my view: A LazyVStack inside a ScrollView displays the images.
struct LazyScrollView: View {
@Environment(\.modelContext) private var modelContext
@State private var isShowingPhotosPicker: Bool = false
@State private var selectedItems: [PhotosPickerItem] = []
@Query private var items: [Item]
var body: some View {
NavigationStack {
ScrollView {
LazyVStack {
ForEach(items) { item in
NavigationLink {
Image(uiImage: UIImage(data: item.photo)!)
.resizable()
.scaledToFit()
} label: {
Image(uiImage: UIImage(data: item.photo)!)
.resizable()
.scaledToFit()
}
}
}
}
.navigationTitle("LazyScrollView")
.photosPicker(isPresented: $isShowingPhotosPicker, selection: $selectedItems, maxSelectionCount: 100, matching: .images)
.onChange(of: selectedItems) {
Task {
for item in selectedItems {
if let data = try await item.loadTransferable(type: Data.self) {
let newItem = Item(photo: data)
modelContext.insert(newItem)
}
}
try? modelContext.save()
selectedItems = []
}
}
}
}
}
Based on this:
- How can I prevent SwiftUI from loading all the binary data (photo) into memory when the whole view is scrolled until the last item?
- Why does SwiftUI not free memory from the images that are not being displayed?
Any insights or suggestions would be greatly appreciated. Thank you!
I will put the full view code in the comments so anyone can test if needed.