skip to Main Content

I’m working with UIImagePickerController for the editing feature it offers but I’m running into one slight issue. If I replace the image a few times, about 5-6 it will crash and return warnings like this:

<0x100d08660> Gesture: System gesture gate timed out.

[u 0A3027E7-E344-4002-9629:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin interrupted while in use.

[u 0A3027E7-E344-4002-9629:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin invalidated while in use.

-[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

-[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

-[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

This is the code:

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    var sourceType: UIImagePickerController.SourceType = .photoLibrary
    
    @Binding var selectedImage: UIImage
    @Binding var showSheet: Bool
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        
        let imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = true
        imagePicker.sourceType = sourceType
        imagePicker.delegate = context.coordinator
        
        let appearance = UINavigationBarAppearance()
        appearance.configureWithTransparentBackground()
        appearance.backgroundColor = .systemBackground
        appearance.titleTextAttributes = [.foregroundColor: UIColor.systemBackground]
        appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.systemBackground]
        
        imagePicker.navigationBar.tintColor = .white
        imagePicker.navigationBar.standardAppearance = appearance
        imagePicker.navigationBar.compactAppearance = appearance
        imagePicker.navigationBar.scrollEdgeAppearance = appearance
        
        return imagePicker
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        var parent: ImagePicker
        
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
                parent.selectedImage = image
            }
            
            parent.showSheet = false
        }
        
    }
}

struct ImagePickerTest: View {
    @State private var image = UIImage()
    @State private var showSheet = false
    
    var body: some View {
        VStack {

            Button("Change photo") {
                showSheet = true
            }
            Image(uiImage: self.image)
                .resizable()
                .frame(width: 100, height: 100)
                .background(Color.gray)
                .scaledToFit()
                .clipShape(Circle())
        }
        .sheet(isPresented: $showSheet) {
            ImagePicker(sourceType: .photoLibrary, selectedImage: $image, showSheet: $showSheet)
                .ignoresSafeArea(.all)
        }
    }
}

Not sure where to go from here. This is the first time I’m seeing this.

I’ve used the PhotosPicker from the PhotosUI package and it never fails like this. Only downside is it doesn’t offer an editing mode like UIImagePickerController.

I’m wondering is there some "cleanup" that I need to be doing after I select an image or before I select the next one?

2

Answers


  1. Although I haven’t experienced any crashes with your code even changing the image 10 times, I believe you. I still saw memory usage increase every time I selected a new photo. I guess this is a memory leak. You could try mitigate that by compressing the image you’re loading. To do so you could add this property to your ImagePicker struct:

    var size: CGSize = .init(width: 300, height: 300)
    

    This will allow you to chose the size of your image.
    Then in the imagePickerController fuction you apply the actual compression:

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
                parent.selectedImage = image.preparingThumbnail(of: CGSize(width: parent.size.width / 2,
                                                                           height: 300))!
            }
            parent.showSheet = false
        }
    

    Also, you will need to update your main View to have a GeometryReader to extract the size from:

    GeometryReader {
            let size = $0.size
            VStack(alignment: .center) {
                
                Button("Change photo") {
                    showSheet = true
                }
                Image(uiImage: self.image)
                    .resizable()
                    .frame(width: 100, height: 100)
                    .background(Color.gray)
                    .scaledToFit()
                    .clipShape(Circle())
            }
            .sheet(isPresented: $showSheet) {
                ImagePicker(sourceType: .photoLibrary, 
                            selectedImage: $image,
                            showSheet: $showSheet,
                            size: size)
                    .ignoresSafeArea(.all)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
    

    Let me know how this works for you and if it still keeps crashing!

    Login or Signup to reply.
  2. It seems like you might be facing memory-related issues with the UIImagePickerController. To address the problem, you can try implementing an additional cleanup step picker.dismiss to ensure you release the ImagePicker reference properly and defer block will update showSheet before exit.

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        defer {
            parent.showSheet = false
        }
        
        guard let editedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
            return
        }
        
        parent.selectedImage = editedImage
        picker.dismiss(animated: true, completion: nil)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search