Hi,
I am trying to use UIDocumentPickerViewController to select a folder in a 3rd party file provider as a "default save location". The goal would be to have that folder be the automatic location to save to whenever the app needs to write a file out to disk, instead of the app's Documents directory.
When I present the UIDocumentPickerViewController for selecting folders, however, every 3rd party file provider is grayed out. Only "On this Device" and "iCloud Drive" are available.
let controller = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
controller.delegate = self
controller.allowsMultipleSelection = false
present(controller, animated: true, completion: nil)
The documentation states:
"With iOS 13, users can select a directory from any of the available file providers using a UIDocumentPickerViewController."
It seems strange that this is specifically called out in the docs, but it doesn't work at all. One hypothesis that I have is that there is some confusion in the system between kUTTypeFolder and kUTTypeDirectory which is causing this issue. But it's weird that this would be an issue from iOS 13 through iOS 15.
As a workaround, I also tried moving/copying a temporary directory with UIDocumentPickerViewController to the 3rd party provider, and using the resulting security-scoped URL to create new files. However, it seems that it doesn't grant proper permissions because whenever I try to create files in that folder, it throws an error claiming the file doesn't exist (duh, that's what I'm trying to do.)
let temporary = try! TemporaryFile(creatingTempDirectoryForFilename: "placeholder")
FileManager.default.createFile(atPath: temporary.fileURL.path, contents: nil, attributes: nil)
let controller = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
controller.delegate = self
controller.allowsMultipleSelection = false
present(controller, animated: true, completion: nil)
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let folderURL = urls.first!
let randomNumber = String(format: "%X", arc4random())
guard folderURL.startAccessingSecurityScopedResource() else {
Swift.debugPrint("Cannot access security-scoped URL: \(folderURL)")
return
}
defer { folderURL.stopAccessingSecurityScopedResource() }
let fileURL = folderURL.appendingPathComponent(randomNumber).appendingPathExtension("txt")
var error: NSError?
NSFileCoordinator().coordinate(writingItemAt: fileURL, options: .forReplacing, error: &error) { fileURL in
let data = Data(randomNumber.utf8)
do {
try data.write(to: fileURL, options: [])
} catch {
print("error writing file:")
print(error)
}
}
}
error writing file:
Error Domain=NSCocoaErrorDomain Code=4 "The file “3A7F4A2.txt” doesn’t exist." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/D9D4024B-AD43-4B57-920B-D8E2B5ED7645/File Provider Storage/non-file/d_LOCAL-0A6C7195-23D8-43AE-9CBC-B84F063E2B44/3A7F4A2.txt, NSUnderlyingError=0x2817ea100 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Does anyone have an idea for a workaround for this issue? Are there any known 3rd party file providers which are known to work? Is there any reason this would be disallowed? Finally, does anyone have an idea how I could implement the intended functionality in a way that I haven't thought of, yet?
Post
Replies
Boosts
Views
Activity
Since upgrading to Xcode 12 and iOS 14, I have been getting warnings that my Transformable properties in Core Data should be using NSSecureCoding.
CoreData: fault: One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead. At some point, Core Data will default to using "NSSecureUnarchiveFromData" when nil is specified, and transformable properties containing classes that do not support NSSecureCoding will become unreadable.
However, after adopting NSSecureCoding, I still receive this message. I have implemented NSSecureCoding across the board, and have created a single subclass of NSSecureUnarchiveFromDataTransformer that allows all of these conforming custom data types as top level classes. I register this subclass as a value transformer before constructing my Core Data container. And I have set all the "Transformer" attributes in my managed object model to my custom transformer's name. This has not seemed to make a difference to Core Data, though. I still receive the warnings in my logs. Does anybody else have this problem, or any idea how to resolve?