问题
I'm new to FileManager
in iOS.
I'm trying to create a simple app: there's a list of files, and when the user press a cell the the file opens. The user can also add new files.
This is what I currently have:
class TableViewController: UITableViewController, UIDocumentPickerDelegate {
var urls: [URL] = []
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
@IBAction func newButtonPressed(_ sender: Any) {
let types = UTType(tag: "pdf", tagClass: .filenameExtension, conformingTo: nil)!
let controller = UIDocumentPickerViewController(forOpeningContentTypes: [types])
controller.delegate = self
self.present(controller, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
self.storeAndShare(withURL: url)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return urls.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = urls[indexPath.row].localizedName
return cell
}
lazy var documentInteractionController: UIDocumentInteractionController = {
let vc = UIDocumentInteractionController()
vc.delegate = self
return vc
}()
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
share(url: self.urls[indexPath.row])
}
func storeAndShare(withURL url: URL) {
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let direcotryURL = URL(string: FileManager.default.currentDirectoryPath)!
let newURL = direcotryURL.appendingPathComponent(response?.suggestedFilename ?? "fileName.pdf")
do {
try data.write(to: newURL)
} catch let err {
print("ERROR: \(err).")
// Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
return
}
DispatchQueue.main.async {
/// STOP YOUR ACTIVITY INDICATOR HERE
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
}.resume()
}
}
extension TableViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}
I have problems with the storeAndShare()
function. I'm trying to copy the selected file to the app's directory, and then add the new URL to the urls list (self.urls
).
But it doesn't work, and gives me an error in data.write:
Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
Why is this happening? and how can I achieve what I need? thanks in advance
回答1:
The most significant mistake is currentDirectoryPath
. You must not use it to get the path to the Documents directory. You have to call url(for:in:appropriateFor:create:
or urls(for:in:)
of FileManager
And – if we are talking about local files – URLSession
is the wrong way, too.
func storeAndShare(with url: URL) {
let directoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let newURL = directoryURL.appendingPathComponent(url.lastPathComponent)
do {
try FileManager.default.copyItem(at: url, to: newURL)
DispatchQueue.main.async {
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
} catch {
print("ERROR: \(error).")
}
}
回答2:
"/doc.pdf"
Is not writable for you.
Get the documents directory:
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
And save your file there (instead of using currentDirectoryPath
).
来源:https://stackoverflow.com/questions/65407772/how-to-copy-selected-file-to-apps-directory