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

SwiftUI封装UIDocumentPickerViewController内存泄漏问题求助

Fixing Memory Leak in UIDocumentPickerViewController Wrapped in UIViewControllerRepresentable

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 Coordinator now holds a weak reference to the parent DocumentPickerView, eliminating any potential strong cycles between the view and its coordinator.
  • Clear Delegate on Completion/Cancellation: The critical fix is setting controller.delegate = nil in both delegate callbacks. UIDocumentPickerViewController holds a strong reference to its delegate, and when the sheet dismisses, the system doesn’t always clean this up automatically—leading to leaked instances like UIDocumentBrowserViewController and DOCRemoteViewController. Clearing the delegate breaks this strong cycle, allowing all related objects to be deallocated properly.
  • Reusable Callback (Optional): I added an onFileSelected closure 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:27:29