I'm playing around with the new photo picker in SwiftUI 2 and I made a simple app to show the imported images in a LazyVGrid but when scrolling down, if I imported around 150 images the app finish all the memory and it crashes (Terminated due to memory issue).
I tried the same with a LazyVStack and List but they have the same problem, I was expecting lazy items to release all the cells that goes off screen from the memory but it doesn't look like it's working.
Is this a bug or am I doing something wrong?
Here's my code:
import SwiftUI
struct Media: Identifiable {
var id = UUID()
var image: Image
}
struct ContentView: View {
@State var itemProviders: [NSItemProvider] = []
@State private var showingPhotoPicker: Bool = false
let columns = [
GridItem(.adaptive(minimum: 100, maximum: 100), spacing: 8)
]
@State var medias: [Media] = []
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns, spacing: 8) {
ForEach(medias) { media in
media.image
.resizable()
.scaledToFill()
.frame(width: 100, height: 100, alignment: .center)
.clipped()
}
}
}
.navigationBarTitle("Images \(medias.count)")
.navigationBarItems(leading: Button(action: {
loadImages()
}, label: {
Text("Import \(itemProviders.count) images")
}), trailing: Button(action: {
showingPhotoPicker.toggle()
}, label: {
Image(systemName: "photo.on.rectangle.angled")
}))
.sheet(isPresented: $showingPhotoPicker) {
MultiPHPickerView(itemProviders: $itemProviders)
}
}
}
func loadImages() {
for item in itemProviders {
if item.canLoadObject(ofClass: UIImage.self) {
item.loadObject(ofClass: UIImage.self) { image, error in
DispatchQueue.main.async {
guard let image = image as? UIImage else {
return
}
medias.append(Media(image: Image(uiImage: image)))
}
}
}
}
}
}
And the PhotoPickerView:
import SwiftUI
import PhotosUI
struct MultiPHPickerView: UIViewControllerRepresentable {
@Environment(\.presentationMode) private var presentationMode
@Binding var itemProviders: [NSItemProvider]
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration()
configuration.filter = .images
configuration.selectionLimit = 0
let controller = PHPickerViewController(configuration: configuration)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController( _ uiViewController: PHPickerViewController, context: Context) {}
class Coordinator: NSObject, PHPickerViewControllerDelegate {
@Environment(\.presentationMode) private var presentationMode
var parent: MultiPHPickerView
init( _ parent: MultiPHPickerView ) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss( animated: true )
self.parent.itemProviders = results.map(\.itemProvider)
}
}
}