LazyVGrid, List, LazyStacks don't release views from memory?

933 views Asked by At

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)
        }
    }
    
}
0

There are 0 answers