1

I built an iOS app in Swift, and I'm adding some functionality for macOS Catalyst.

In my app I create a .txt file upon clicking a button. I want to present a UIDocumentPickerViewController that allows the user to specify the save directory, and file name. So far I am only able to display the UIDocumentPickerViewController without the option to name the file or save. Is UIDocumentPickerViewController the right view controller to accomplish this? If so, how do I specify the save directory and file name?

Here is the code I'm using to present the UIDocumentPickerViewController

#if targetEnvironment(macCatalyst)
            
            let str = "Hello boxcutter"
            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
            let fileURL = documentsURL.appendingPathComponent("boxCutter.txt")
            try! str.write(to: fileURL!, atomically: true, encoding: String.Encoding.utf8)
            
            let types: [String] = [kUTTypeFolder as String]
            let documentPicker = UIDocumentPickerViewController(documentTypes: types, in: .open)
            documentPicker.delegate = self
            documentPicker.allowsMultipleSelection = false
            documentPicker.modalPresentationStyle = .formSheet
            self.present(documentPicker, animated: true, completion: nil)

#endif
Austin Berenyi
  • 1,013
  • 2
  • 13
  • 25
  • `UIDocumentPickerViewController` is usually used to import/open a file. You should first save it locally and then use `UIDocumentIteractionController` to allow the user to share the local file but I have never tested that with Catalyst. https://stackoverflow.com/questions/46456481/how-to-write-a-file-to-a-folder-located-at-apples-files-app-in-swift/46457518#46457518 – Leo Dabus Jul 14 '20 at 15:08

1 Answers1

1

You can use NSSavePanel to ask the user where to save the file. It's a macOS API that isn't directly accessible from Catalyst apps, but you can create a macOS plugin that has access to macOS API as explained here. Or use a library like Dynamic (Full disclosure: I'm the author) to achieve the same thing without a plugin:

let nsWindow = Dynamic.NSApplication.sharedApplication.delegate.hostWindowForUIWindow(view.window)

let panel = Dynamic.NSSavePanel()
panel.nameFieldStringValue = "boxCutter.txt"
panel.beginSheetModalForWindow(nsWindow, completionHandler: { response in
    if response == 1 /*OK*/ {
        print("file URL: ", panel.URL.asURL)
    }
} as ResponseBlock)

typealias ResponseBlock = @convention(block) (_ response: Int) -> Void
Hejazi
  • 16,587
  • 9
  • 52
  • 67