3

该应用程序是为 iOS 构建的。我希望用户从它的目录中选择一个文件并获取所选文件的 url。Apple 建议UIDocumentPickerViewController解决此问题。我把它包起来了UIViewControllerRepresentable,所以这是第一个我可能会出错的地方

import SwiftUI
import MobileCoreServices

struct DocumentPickerView: UIViewControllerRepresentable {
    func makeCoordinator() -> Coordinator {
        return DocumentPickerView.Coordinator()
    }

    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 {
        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            print("url: \(urls[0].absoluteString )")
        }
    }
}

struct ContentView: View {
    @State var showPicker = false

    var body: some View {
        Button(action: {
            self.showPicker.toggle()
        }, label: {
            Text("Push me")
        })
        .sheet(isPresented: self.$showPicker) {
            DocumentPickerView()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

我认为存在问题的原因是 Xcode 仪器显示内存泄漏,这里是跟踪:

 32 Bytes  100.0%   1       start
 32 Bytes  100.0%   1        main
 32 Bytes  100.0%   1         UIApplicationMain
 32 Bytes  100.0%   1          GSEventRunModal
 32 Bytes  100.0%   1           CFRunLoopRunSpecific
 32 Bytes  100.0%   1            __CFRunLoopRun
 32 Bytes  100.0%   1             __CFRunLoopDoObservers
 32 Bytes  100.0%   1              __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
 32 Bytes  100.0%   1               _afterCACommitHandler
 32 Bytes  100.0%   1                _cleanUpAfterCAFlushAndRunDeferredBlocks
 32 Bytes  100.0%   1                 _runAfterCACommitDeferredBlocks
 32 Bytes  100.0%   1                  __56-[UIPresentationController runTransitionForCurrentState]_block_invoke.478
 32 Bytes  100.0%   1                   _UIViewControllerTransitioningRunCustomTransition
 32 Bytes  100.0%   1                    +[UIView(Animation) _setAlongsideAnimations:toRunByEndOfBlock:]
 32 Bytes  100.0%   1                     ___UIViewControllerTransitioningRunCustomTransition_block_invoke.648
 32 Bytes  100.0%   1                      +[UIInputResponderController _pinInputViewsForInputResponderController:onBehalfOfResponder:duringBlock:]
 32 Bytes  100.0%   1                       ___UIViewControllerTransitioningRunCustomTransition_block_invoke_2
 32 Bytes  100.0%   1                        -[UIViewControllerBuiltinTransitionViewAnimator animateTransition:]
 32 Bytes  100.0%   1                         -[UITransitionView transition:fromView:toView:removeFromView:]
 32 Bytes  100.0%   1                          -[UITransitionView _startTransition:withDuration:]
 32 Bytes  100.0%   1                           +[UIView(UIViewAnimationWithBlocks) conditionallyAnimate:withAnimation:layout:completion:]
 32 Bytes  100.0%   1                            __50-[UITransitionView _startTransition:withDuration:]_block_invoke.169
 32 Bytes  100.0%   1                             +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:]
 32 Bytes  100.0%   1                              +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:]
 32 Bytes  100.0%   1                               +[UIViewAnimationState popAnimationState]
 32 Bytes  100.0%   1                                -[UIViewAnimationState pop]
 32 Bytes  100.0%   1                                 -[UIViewAnimationState _runAlongsideAnimations]
 32 Bytes  100.0%   1                                  __63+[UIView(Animation) _setAlongsideAnimations:toRunByEndOfBlock:]_block_invoke
 32 Bytes  100.0%   1                                   -[_UIViewControllerTransitionContext __runAlongsideAnimations]
 32 Bytes  100.0%   1                                    -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:]
 32 Bytes  100.0%   1                                     __54-[_UISheetPresentationController transitionWillBegin:]_block_invoke.345
 32 Bytes  100.0%   1                                      +[UIView(Animation) performWithoutAnimation:]
 32 Bytes  100.0%   1                                       __54-[_UISheetPresentationController transitionWillBegin:]_block_invoke_2
 32 Bytes  100.0%   1                                        -[_UISheetLayoutInfo _layout]
 32 Bytes  100.0%   1                                         -[_UISheetPresentationController _sheetLayoutInfoLayout:]
 32 Bytes  100.0%   1                                          -[UIView(Hierarchy) layoutBelowIfNeeded]
 32 Bytes  100.0%   1                                           CA::Layer::layout_if_needed(CA::Transaction*)
 32 Bytes  100.0%   1                                            -[CALayer layoutSublayers]
 32 Bytes  100.0%   1                                             -[UIView(CALayerDelegate) layoutSublayersOfLayer:]
 32 Bytes  100.0%   1                                              @objc _UIHostingView.layoutSubviews()
 32 Bytes  100.0%   1                                               _UIHostingView.layoutSubviews()
 32 Bytes  100.0%   1                                                ViewRendererHost.render(interval:updateDisplayList:)
 32 Bytes  100.0%   1                                                 closure #1 in ViewRendererHost.render(interval:updateDisplayList:)
 32 Bytes  100.0%   1                                                  closure #1 in closure #1 in ViewRendererHost.render(interval:updateDisplayList:)
 32 Bytes  100.0%   1                                                   ViewGraph.updateOutputs(at:)
 32 Bytes  100.0%   1                                                    closure #1 in ViewGraph.updateOutputs(at:)
 32 Bytes  100.0%   1                                                     ViewGraph.runTransaction(in:)
 32 Bytes  100.0%   1                                                      AG::Subgraph::update(unsigned int)
 32 Bytes  100.0%   1                                                       AG::Graph::update_attribute(unsigned int, bool)
 32 Bytes  100.0%   1                                                        AG::Graph::UpdateStack::update()
 32 Bytes  100.0%   1                                                         partial apply
 32 Bytes  100.0%   1                                                          protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance PlatformViewChild<A>
 32 Bytes  100.0%   1                                                           PlatformViewChild.update(context:)
 32 Bytes  100.0%   1                                                            closure #1 in PlatformViewChild.update(context:)
 32 Bytes  100.0%   1                                                             swift_weakInit
 32 Bytes  100.0%   1                                                              swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::formWeakReference()
 32 Bytes  100.0%   1                                                               operator new(unsigned long)
 32 Bytes  100.0%   1                                                                malloc

在分配时多次调用我有这样的实体失去了记忆:

Category                                            Persistent  # Persistent    # Transient Total Bytes
UIDocumentBrowserViewController                     22,50 KiB       15              0       22,50 KiB
DOCRemoteViewController                             22,50 KiB       15              0       22,50 KiB
_UIResilientRemoteViewContainerViewController       13,36 KiB       15              0       13,36 KiB
_UIRemoteView                                       6,80 KiB        15              0       6,80 KiB
_UISizeTrackingView                                 6,56 KiB        15              0       6,56 KiB
DOCRemoteBarButtonTrackingView                      5,62 KiB        15              0       5,62 KiB
DOCConfiguration                                    2,58 KiB        15              0       2,58 KiB
DOCRemoteContext                                    1,88 KiB        15              0       1,88 KiB
_UIViewServiceInterface                             1,41 KiB        15              0       1,41 KiB
__NSXPCInterfaceProxy__NSExtensionContextVending    1,17 KiB        15              0       1,17 KiB
UISystemDefaultTextInputAssistantItem               1,17 KiB        15              0       1,17 KiB
UIKeyboardBIUImageGenerator                         960 Bytes       15              0       960 Bytes
_UIViewServiceReplyControlProxy                     720 Bytes       15              0       720 Bytes
Swift.__SwiftDeferredNSArray                        480 Bytes       15              0       480 Bytes
DOCRemoteBarButton                                  480 Bytes       15              0       480 Bytes
NSWeakObjectValue                                   480 Bytes       15              0       480 Bytes
_UIRemoteViewService                                480 Bytes       15              0       480 Bytes
_UIViewServiceImplicitAnimationEncodingProxy        480 Bytes       15              0       480 Bytes
DOCWeakProxy                                        240 Bytes       15              0       240 Bytes

升级版:

刚开始反馈解决这个问题,但是发现没有类似的问题,所以如果你有同样的问题也请报告

4

1 回答 1

0

这绝对是 Apple 的错误,因此值得向他们提交反馈。

同时,这是适用于大多数用例的安全解决方法。使用 Xcode 11.4 / iOS 13.4 测试。这个想法是使用共享文档选择器实例,并在每次调用时重新配置它。

struct DocumentPickerView: UIViewControllerRepresentable {
    static let picker = UIDocumentPickerViewController(documentTypes: [String(kUTTypeItem)], in: .import)

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        Self.picker.allowsMultipleSelection = false
        Self.picker.delegate = context.coordinator
        return Self.picker
    }

    // ... other code no changes
于 2020-06-19T12:26:24.530 回答