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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:56:14