Search code examples
swiftfirebaseswiftuiuiviewcontrollerrepresentablephpickerviewcontroller

How to upload multiple image on firebase using Swift's PHPickerController


so in Swift, you have the ability to upload an image/video with ease using UIImageViewController. I did research and came across PHPickerController and I am trying to incorporate that into my code - for the reasoning being that I want multiple images/videos selected and once user presses "button" it pushes that batch to firebase cloud. I have been struggling with this for sometime now. Any sample swift file of doing just this would be much appreciated.


Solution

  • This worked for me.

    Note: Make sure that the images you are selecting from the photoLibrary are not the default ones that come with xCode. Some of the default images do not work because they don't have a file location.

    SwiftUI Solution

    Here is how you call the PHPickerViewController:

    struct PHPicker: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> PHPickerViewController {
        var config = PHPickerConfiguration()
        config.selectionLimit = 5
        config.filter = PHPickerFilter.images
        
        let pickerViewController = PHPickerViewController(configuration: config)
        pickerViewController.delegate = context.coordinator
        return pickerViewController
    }
    
    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
    }
    
    class something: NSObject, PHPickerViewControllerDelegate {
        
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            
            var fileName: Int = 5
            for result in results {
                
                // Get all the images that you selected from the PHPickerViewController
                result.itemProvider.loadObject(ofClass: UIImage.self) { object, error in
                    // Check for errors
                    if let error = error {
                        print("Sick error dawg \(error.localizedDescription)")
                    } else {
                        // Convert the image into Data so we can upload to firebase
                        if let image = object as? UIImage {
                            let imageData = image.jpegData(compressionQuality: 1.0)
                            
                            // You NEED to make sure you somehow change the name of each picture that you upload which is why I am using the variable "count".
                            // If you do not change the filename for each picture you upload, it will try to upload the file to the same file and it will give you an error.
                            Storage.storage().reference().child("fileName").child("\(fileName)").putData(imageData!)
                            fileName += 1
                            print("Uploaded to firebase")
                        } else {
                            print("There was an error.")
                        }
                    }
                }
            }
        }
    }
    
    func makeCoordinator() -> something {
        return something()
    }
    

    }

    Here is how I present the sheet:

    struct PresentMyPicker: View {
    
    @State var presentSheet: Bool = false
    
    var body: some View {
        VStack {
            Button {
                presentSheet.toggle()
            } label: {
                Text("Click me")
            }
        }
        .sheet(isPresented: $presentSheet) {
            PHPicker()
        }
    }
    

    }

    UIKit solution

    This is how I present the PHPickerViewController when they tap the button:

        func setupView() {
        var config = PHPickerConfiguration()
        config.selectionLimit = 5
        config.filter = PHPickerFilter.images
        
        let pickerViewController = PHPickerViewController(configuration: config)
        pickerViewController.delegate = self
        
        view.addSubview(button)
        button.addAction(UIAction() { _ in
            self.present(pickerViewController, animated: true)
        }, for: .touchUpInside)
    }
    

    Here is my delegate function that runs after you click "Add" with the selected images you want to upload.

    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        var fileName: Int = 1
        for result in results {
            
            // Get all the images that you selected from the PHPickerViewController
            result.itemProvider.loadObject(ofClass: UIImage.self) { object, error in
                // Check for errors
                if let error = error {
                    print("Sick error dawg \(error.localizedDescription)")
                } else {
                    // Convert the image into Data so we can upload to firebase
                    if let image = object as? UIImage {
                        let imageData = image.jpegData(compressionQuality: 1.0)
                        
                        // You NEED to make sure you somehow change the name of each picture that you upload which is why I am using the variable "fileName".
                        // If you do not change the filename for each picture you upload, it will try to upload all the selected images to the same file location and give you an error.
                        Storage.storage().reference().child("CollectionName").child("\(fileName)").putData(imageData!)
                        fileName += 1
                    } else {
                        print("There was an error.")
                    }
                }
            }
        }
    }
    

    Also if you are wanting to upload videos to firebase and having trouble take a look at this example it took me forever to figure this out. Uploading Videos to firebase correctly.