1
votes

I have this code for show picker with Catalyst in MacOS:

final class DocumentPicker: NSObject, UIViewControllerRepresentable, ObservableObject {
    typealias UIViewControllerType = UIDocumentPickerViewController
    @Published var urlsPicked = [URL]()

    lazy var viewController:UIDocumentPickerViewController = {
        // For picked only folder
        let vc = UIDocumentPickerViewController(documentTypes: ["public.folder"], in: .open)
        vc.allowsMultipleSelection = false
        vc.delegate = self
        return vc
    }()        
    ........

and:

struct ContentView: View {
    @ObservedObject var picker = DocumentPicker()
    @State private var urlPick = ""

    var body: some View {
        HStack {
            Text(urlPicked())
                .padding()
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.white, lineWidth: 1)
                )
            TextField("", text: $urlPick)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .font(.system(size: 10))
                .disabled(true)
            Spacer()
            Button(action: {
                #if targetEnvironment(macCatalyst)
                let viewController = UIApplication.shared.windows[0].rootViewController!
                viewController.present(self.picker.viewController, animated: true)
                self.picker.objectWillChange.send()
                #endif
                print("Hai premuto il pulsante per determinare il path della GeoFolder")
            }) {
                Image(systemName: "square.and.arrow.up")
            }
        }
        .padding()
    }

    private func urlPicked() -> String {
        var urlP = ""
        if picker.urlsPicked.count > 0 {
            urlP = picker.urlsPicked[0].path
            urlPick = picker.urlsPicked[0].path
        }
        return urlP
    }
}

If I run the above code I get the chosen correct path in text, while in textfield nothing and also I have the error in urlPick = picker.urlsPicked[0].path: Modifying state during view update, this will cause undefined behavior. How can I modify the code to show the correct path chosen also in textfield?

2

2 Answers

1
votes

have the error in urlPick = picker.urlsPicked[0].path: Modifying state during view update, this will cause undefined behavior. How can I modify the code to show the correct path chosen also in textfield?

Try the following

    if picker.urlsPicked.count > 0 {
        urlP = picker.urlsPicked[0].path
        DispatchQueue.main.async {
            urlPick = picker.urlsPicked[0].path
        }
    }
0
votes

For anyone seeking to create a MacOS Document Picker with READ-ONLY entitlements, please use the following solution:

import Foundation
import UIKit

extension ViewController: UIDocumentBrowserViewControllerDelegate, UIDocumentPickerDelegate {
    
    @objc func presentDocumentPicker() {
        
        if operatingSystem == .macintosh {
            let documentPicker = UIDocumentBrowserViewController(forOpening: [.pdf])
            documentPicker.delegate = self
            documentPicker.allowsDocumentCreation = false
            documentPicker.allowsPickingMultipleItems = false
            // Present the document picker.
            present(documentPicker, animated: true, completion: nil)
        } else {
            let documentsPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.pdf])
            documentsPicker.delegate = self
            documentsPicker.allowsMultipleSelection = false
            documentsPicker.modalPresentationStyle = .fullScreen
            self.present(documentsPicker, animated: true, completion: nil)
        }

    }
    
    
    func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) {
        guard let url = documentURLs.first, url.startAccessingSecurityScopedResource() else { return }
        defer {
            DispatchQueue.main.async {
                url.stopAccessingSecurityScopedResource()
            }
        }
        debugPrint("[DocumentPicker] Selected Item with URL : ", url)
        controller.dismiss(animated: true)
    }
    
    public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        guard let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
        defer {
            DispatchQueue.main.async {
                url.stopAccessingSecurityScopedResource()
            }
        }
        debugPrint("[DocumentPicker] Selected Item with URL : ", url)
        controller.dismiss(animated: true)
    }

    public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
        controller.dismiss(animated: true)
    }
}

Please note that in the event that the entitlements are read-write (i.e. you are also allowing the user to save files to the computer) - then you can simply use a UIDocumentPicker (the non .macintosh example in my snippet).