SwiftUI封装UIDocumentPickerViewController内存泄漏问题求助
I ran into an almost identical memory leak issue when wrapping UIDocumentPickerViewController for SwiftUI, and the root cause is a strong reference cycle between the picker and its delegate (your Coordinator class). Here's a reliable solution to fix it:
Modified Code with Leak Resolutions
import SwiftUI import MobileCoreServices struct DocumentPickerView: UIViewControllerRepresentable { // Optional: Add a callback to pass selected URL back to parent view var onFileSelected: ((URL) -> Void)? func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let picker = UIDocumentPickerViewController(documentTypes: [String(kUTTypeItem)], in: .import) picker.allowsMultipleSelection = false picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) { } class Coordinator: NSObject, UIDocumentPickerDelegate { // Use weak reference to avoid accidental strong cycles with parent view weak var parent: DocumentPickerView? init(parent: DocumentPickerView) { self.parent = parent } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let url = urls.first else { return } print("url: \(url.absoluteString)") parent?.onFileSelected?(url) // Break strong reference cycle by clearing delegate controller.delegate = nil } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { // Don't forget to clean up delegate on cancellation too controller.delegate = nil } } } struct ContentView: View { @State var showPicker = false var body: some View { Button(action: { showPicker.toggle() }, label: { Text("Push me") }) .sheet(isPresented: $showPicker) { DocumentPickerView { url in // Handle the selected URL here in parent view print("Received URL in parent: \(url)") } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
Key Changes & Why They Work
- Weak Parent Reference: The
Coordinatornow holds aweakreference to the parentDocumentPickerView, eliminating any potential strong cycles between the view and its coordinator. - Clear Delegate on Completion/Cancellation: The critical fix is setting
controller.delegate = nilin both delegate callbacks.UIDocumentPickerViewControllerholds a strong reference to its delegate, and when the sheet dismisses, the system doesn’t always clean this up automatically—leading to leaked instances likeUIDocumentBrowserViewControllerandDOCRemoteViewController. Clearing the delegate breaks this strong cycle, allowing all related objects to be deallocated properly. - Reusable Callback (Optional): I added an
onFileSelectedclosure to make the component more flexible, letting you pass the selected URL directly to the parent view instead of relying on print statements.
Additional Context
You mentioned you’ve already filed feedback with Apple—this appears to be an edge case in the SwiftUI/UIKit interop layer where the document picker’s delegate isn’t properly released when the sheet is dismissed. Manually clearing the delegate is a reliable workaround until Apple addresses the underlying issue. If others encounter this, encourage them to submit their own feedback to help prioritize a fix.
内容的提问来源于stack exchange,提问作者Paul Kamp

