3

I have a SwiftUI app that is using an image picker wrapped in UIViewControllerRepresentable using the .sheet modifier to display it.

Upon picking the image, the rest of the app more or less grinds to a halt until there is some kind of crash in the background, and everything becomes fast again - more info to follow after the code:

import SwiftUI

struct StylePanel: View {
    
    @Binding var image: Image?

    @State var inputImage: UIImage? = nil
    @State var showImagePicker: Bool

    func loadImage() {
        guard let inputImage = inputImage else { return }
        image = Image(uiImage: inputImage)
    }
    
    var body: some View {
        
        VStack {
            // Rest of view not shown


            Button(action: {
                self.showImagePicker = true
            }, label: {
                Text("Choose image...")
            })
        }
        .sheet(isPresented: self.$showImagePicker, onDismiss: loadImage){
            ImagePicker(image: self.$inputImage)
        }
    }
}

ImagePicker.swift:

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    @Environment(\.presentationMode) var presentationMode
    @Binding var image: UIImage?

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

    }
        
    func makeCoordinator() -> ImagePickerCoordinator {
        return ImagePickerCoordinator(self)
    }
}


class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    let parent: ImagePicker

    init(_ parent: ImagePicker) {
        self.parent = parent
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        if let uiImage = info[.originalImage] as? UIImage {
            parent.image = uiImage
        }

        parent.presentationMode.wrappedValue.dismiss()
    }
}

Once the image is selected, it displays fine in the parent, but other actions such as dragging or modifying state are really janky. The app is very unresponsive until eventually something strange happens – there is some kind of viewServiceDidTerminateWithError crash in the background and everything starts to behave perfectly again, performance returns to normal. Subsequent reloads of the image picker make it even worse until the same thing happens – background crash followed by normal performance.

This is the error after which performance returns to normal:

[ServicesDaemonManager] interruptionHandler is called. -[FontServicesDaemonManager connection]_block_invoke
[xpc] XPC error talking to pkd: Connection interrupted
[lifecycle] [u 123223B6-8A6C-4BC3-9908-269FA8A8B9E6:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin interrupted while in use.
[lifecycle] [u 123223B6-8A6C-4BC3-9908-269FA8A8B9E6:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin invalidated while in use.
viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}
[Generic] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

It does seem to be directly related to the use of .sheet. When I put the Picker directly in the containing view, it works fine without any issues.

What I'd like to know is how I can properly dispose of the UIImagePickerController modal correctly to stop this performance issue.

Has anyone else experienced this, or know of a solution?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
codewithfeeling
  • 6,236
  • 6
  • 41
  • 53

1 Answers1

0

Have you tried using @StateObject var inputImage instead of @State? This will initialize the image once, avoiding constantly reloading an image as the view changes.

Mozahler
  • 4,958
  • 6
  • 36
  • 56