swiftuiimagepickerios16

Issue with Image picker in swiftui for ios 16


Good day,

I am new to ios development and trying to make an image picker to print out the path of the images to eventually store in a json file but I keep getting this error

Cannot convert value of type 'Binding' to expected argument type 'Binding'

Here is the code that I am busy with.

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let images = info[.originalImage] as? [UIImage] {
                for image in images {
                    print(image)
                }
            }

            parent.$presentationMode.wrappedValue.dismiss()
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    @Binding var presentationMode: PresentationMode
    @Binding var images: [UIImage]

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        picker.sourceType = .photoLibrary
        picker.allowsEditing = false
        picker.modalPresentationStyle = .fullScreen
        picker.mediaTypes = ["public.image"]
        picker.videoQuality = .typeHigh
        picker.videoMaximumDuration = TimeInterval(30)
        picker.modalPresentationStyle = .popover
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
        uiViewController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 0, height: 0))
    }
}

struct ImagePickerView: View {
    @State private var showImagePicker = false
    @State private var images = [UIImage]()

    var body: some View {
        Button("Select Images") {
            self.showImagePicker = true
        }
        .sheet(isPresented: $showImagePicker, onDismiss: {
            self.showImagePicker = false
        }, content: {
            ImagePicker(presentationMode: self.$showImagePicker, images: self.$images)
        })
    }
}

struct ImagePickerViewPreviews: PreviewProvider {
    static var previews: some View {
        ImagePickerView()
    }
}


Solution

  • There are a couple of issues:

    1. You're trying to pass a Binding<Bool> to a Binding<PresentationMode>
    2. You are trying to convert to a [UIImage] instead of UIImage

    You actually don't need the PresentationMode at all -- you can just use the single Bool binding for showImagePicker since all you're doing is trying to effect whether the view is shown or not.

    See comments for the changed lines:

    struct ImagePicker: UIViewControllerRepresentable {
        class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
            let parent: ImagePicker
    
            init(_ parent: ImagePicker) {
                self.parent = parent
            }
    
            func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
                // <-- Here
                if let image = info[.originalImage] as? UIImage {
                    self.parent.images = [image]
                }
    
                parent.showImagePicker = false // <-- Here
            }
        }
    
        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }
    
        @Binding var showImagePicker: Bool // <-- Here
        @Binding var images: [UIImage]
    
        func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.delegate = context.coordinator
            picker.sourceType = .photoLibrary
            picker.allowsEditing = false
            picker.modalPresentationStyle = .fullScreen
            picker.mediaTypes = ["public.image"]
            picker.videoQuality = .typeHigh
            picker.videoMaximumDuration = TimeInterval(30)
            picker.modalPresentationStyle = .popover
            return picker
        }
    
        func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
            uiViewController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 0, height: 0))
        }
    }
    
    struct ImagePickerView: View {
        @State private var showImagePicker = false
        @State private var images = [UIImage]()
    
        var body: some View {
            Button("Select Images") {
                self.showImagePicker = true
            }
            // <-- Here
            .sheet(isPresented: $showImagePicker) {
                ImagePicker(showImagePicker: $showImagePicker, images: $images)
            }
            .onChange(of: images) { newValue in
                print("Images: ", newValue)
            }
        }
    }