You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIImagePickerController多次替换图片后崩溃报错求助

UIImagePickerController多次编辑后崩溃的解决方案

问题现象

使用UIImagePickerController的编辑功能时,替换图片5-6次后程序崩溃,抛出以下错误:

<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}

相关代码如下:

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)
        }
    }
}

问题原因

  1. 未正确销毁Picker实例:原代码仅通过修改showSheet绑定关闭Sheet,但未主动调用UIImagePickerController的dismiss方法,导致Picker实例无法被正确销毁,插件进程资源持续占用,多次重复后触发连接中断。
  2. 循环引用风险:Coordinator强持有parent(ImagePicker实例),可能引发循环引用,导致内存泄漏,进一步加剧资源消耗。
  3. 缺少取消处理逻辑:未实现imagePickerControllerDidCancel代理方法,用户取消选择时Picker同样无法被正确清理。

修复方案

1. 修改Coordinator的引用方式并完善代理方法

将Coordinator中对parent的引用改为弱引用,并实现取消选择的处理逻辑,确保Picker被正确dismiss:

final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    // 改为弱引用避免循环引用
    weak var parent: ImagePicker?

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

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[.editedImage] as? UIImage {
            parent?.selectedImage = image
        }
        // 先dismiss Picker,再更新绑定状态
        picker.dismiss(animated: true) {
            self.parent?.showSheet = false
        }
    }

    // 实现取消选择的代理方法
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true) {
            self.parent?.showSheet = false
        }
    }
}

2. 确保Sheet的正确销毁

SwiftUI的sheet在isPresented变为false时会自动销毁内部的ViewController,但配合主动调用Picker的dismiss,可以确保资源被及时释放,避免插件进程过载。

额外说明

PhotosPicker基于新的PhotosUI框架,采用了更轻量的进程管理机制,因此不会出现此类问题,但它确实缺乏UIImagePickerController的内置编辑功能。上述修改通过规范内存管理和Picker生命周期,即可解决重复编辑后的崩溃问题。

内容的提问来源于stack exchange,提问作者MobileFirst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:33:28