iOS18模拟器中SwiftUI fileImporter冻结问题及替代方案咨询
iOS18模拟器下SwiftUI fileImporter冻结的替代方案
针对你混合Objective-C+UIKit与Swift+SwiftUI的老项目,在iOS18模拟器中fileImporter冻结无响应的问题,推荐以下几种可靠的替代文件选择实现方式:
1. 包装UIKit的UIDocumentPickerViewController
利用UIKit原生的文件选择器,通过UIViewControllerRepresentable将其封装为SwiftUI可用的组件,该方案在iOS18模拟器和真机上均能稳定运行,适配混合项目场景。
封装代码
import SwiftUI import UIKit import UniformTypeIdentifiers struct DocumentPicker: UIViewControllerRepresentable { let allowedContentTypes: [UTType] @Binding var isPresented: Bool let onSelect: (URL) -> Void func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let picker = UIDocumentPickerViewController(forOpeningContentTypes: allowedContentTypes) picker.delegate = context.coordinator // 若需要支持多选,可设置 allowsMultipleSelection = true return picker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, UIDocumentPickerDelegate { private let parent: DocumentPicker init(parent: DocumentPicker) { self.parent = parent } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let selectedURL = urls.first else { return } parent.onSelect(selectedURL) parent.isPresented = false } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { parent.isPresented = false } } }
在SwiftUI视图中使用
struct ContentView: View { @State private var showDocumentPicker = false var body: some View { Button("选择文档") { showDocumentPicker = true } .sheet(isPresented: $showDocumentPicker) { DocumentPicker( allowedContentTypes: [.text, .pdf, .image], isPresented: $showDocumentPicker ) { url in // 处理选中的文件逻辑 print("选中文件路径:\(url.path)") } } } }
2. 针对图片/视频的专用选择器
如果仅需选择图片或视频,可封装UIKit的UIImagePickerController,同样适配iOS18全环境:
封装代码示例
struct ImagePicker: UIViewControllerRepresentable { @Binding var isPresented: Bool @Binding var selectedImage: UIImage? let sourceType: UIImagePickerController.SourceType func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = sourceType picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { private let parent: ImagePicker init(parent: ImagePicker) { self.parent = parent } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[.originalImage] as? UIImage { parent.selectedImage = image } parent.isPresented = false } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { parent.isPresented = false } } }
使用方式
struct MediaPickerView: View { @State private var showImagePicker = false @State private var selectedImage: UIImage? var body: some View { VStack { Button("从相册选择图片") { showImagePicker = true } .sheet(isPresented: $showImagePicker) { ImagePicker( isPresented: $showImagePicker, selectedImage: $selectedImage, sourceType: .photoLibrary ) } if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 200) } } } }
3. 临时兼容方案(针对fileImporter)
若仍想保留fileImporter,可尝试在触发时添加主线程延迟,规避模拟器可能存在的线程阻塞问题:
Button("选择文件") { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { showFileImporter = true } } .fileImporter( isPresented: $showFileImporter, allowedContentTypes: [.text], allowsMultipleSelection: false ) { result in // 处理结果逻辑 }
注:该方案仅为临时 workaround,长期仍推荐使用UIKit封装的组件。
内容的提问来源于stack exchange,提问作者Wonton
相关产品推荐
相关产品推荐

