Search code examples
swiftuiuiimagepickercontroller

I am unsure why my imagePickerController Coordinator is not triggering didFinishPickingMediaWithInfo


I hope this is not a duplicate, but if it is can someone point me in the right direction. I tried different variation of the method and none of my breakpoints are stopping the flow.

PickerView

struct PickerView: UIViewControllerRepresentable {

@Binding var savedImage: Bool
@Binding var savedVideo: Bool
@Binding var video: AVAsset?
@Binding var image: UIImage?
@Environment(\.presentationMode) var isPresented
var sourceType: UIImagePickerController.SourceType?
    
func makeUIViewController(context: Context) -> UIImagePickerController {
    let imagePicker = UIImagePickerController()
    if let type = self.sourceType {
        imagePicker.sourceType = type
        imagePicker.delegate = context.coordinator // confirming the delegate
        imagePicker.mediaTypes = ["public.image", "public.movie"]
    }
    return imagePicker
}

func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {

}

// Connecting the Coordinator class with this struct
func makeCoordinator() -> Coordinator {
    return Coordinator(picker: self)
}
}

Coordinator

class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var picker: PickerView

init(picker: PickerView) {
    self.picker = picker
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let media = info[UIImagePickerController.InfoKey.mediaURL] as? NSURL {
        self.picker.video = AVAsset(url: media.absoluteURL!)
        self.picker.savedVideo = true
    } else if let original = info[.originalImage] as? UIImage {
        self.picker.image = original
        self.picker.savedImage = true
    } else if let metadata = info[UIImagePickerController.InfoKey.mediaMetadata] as? NSDictionary {
        print(metadata)
    }
    self.picker.isPresented.wrappedValue.dismiss()
}

}

I put breakpoints within the last method above and nothing is triggering. Not sure why.

Here is how I implemented the ImagePickerView to present itself

@State private var sourceType: UIImagePickerController.SourceType?
@State private var savedImage: Bool = false
@State private var savedVideo: Bool = false
@State private var isImagePickerDisplay = false
@State var video: AVAsset?
@State var image: UIImage?
var body: some View {
    VStack(spacing: 0) {
        HStack(spacing: 0){
            Spacer()
            Button(action: {
                //Opens up camera app
                self.sourceType = .camera
                self.isImagePickerDisplay.toggle()
            }, label: {
                Image(systemName: "camera")
                    .resizable()
                    .frame(width: 25, height: 25)
                    .foregroundColor(Color("Color2"))
                }).frame(width: 50, height: 50, alignment: .leading)
            Button(action: {
                //Opens up photo library
                self.sourceType = .photoLibrary
                self.isImagePickerDisplay.toggle()
            }, label: {
                Image(systemName: "photo.on.rectangle")
                    .resizable()
                    .frame(width: 25, height: 25)
                    .foregroundColor(Color("Color2"))
            }).frame(width: 50, height: 50, alignment: .leading)
        }
        ZStack{
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: width, height: width, alignment: .center)
            } else if video != nil {
                UploadPlayerView(upload: uploadViewModel,
                                 frame: CGRect(x: 0, y: 0, width: width*3, height: (width*3)*9/16))
            } else {
                //grid().gridStyle(StaggeredGridStyle(.vertical, tracks: 3, spacing: 0))
            }
        }
        .frame(width: width, height: width)
    }
    .sheet(isPresented: $isImagePickerDisplay, content: {
        PickerView(savedImage: $savedImage, savedVideo: $savedVideo, video: $video, image: $image, sourceType: self.sourceType)
    })
}

I am suppose to see my ZStack change views to an image or video depending on the user's selection. I am not getting any change in the video or image variable which made me believe that the Coordinator is not working as intended


Solution

  • You need to assign delegate unconditionally, but you assign it only if sourceType is not nil.

    Here is fixed part

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        if let type = self.sourceType {
            imagePicker.sourceType = type
    
             // probably this line also should be moved out of condition
            imagePicker.mediaTypes = ["public.image", "public.movie"]   // << ??
        }
    
        imagePicker.delegate = context.coordinator // << this one !!
        
        return imagePicker
    }