我是 iOS 中文件管理器的新手。我正在尝试创建一个简单的应用程序:有一个文件列表,当用户按下某个单元格时,文件将打开。用户还可以添加新文件。
不久前我asked a question关于我遇到的另一个错误,我得到了 answer that work on a simulator ,但它在真实设备上不起作用!
我的代码:(错误在 storeAndShare()
中)
typealias UrlLink = String
extension UrlLink {
var url: URL {
var url = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
url.appendPathComponent(self)
return url
}
}
class TableViewController: UITableViewController, UIDocumentPickerDelegate {
var names: [UrlLink] = []
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
}
func urlForFilename(_ filename: String) -> URL {
var url = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
url.appendPathComponent(filename)
return url
}
@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 tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let removedName = self.names.remove(at: indexPath.row)
do {
try FileManager.default.removeItem(atPath: removedName.url.path)
} catch let err {
print("Error while trying to remove the file \(err)")
}
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
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 names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = names[indexPath.row]
if FileManager.default.fileExists(atPath: names[indexPath.row].url.path) {
cell.accessoryType = .disclosureIndicator
} else {
cell.accessoryType = .none
}
return cell
}
lazy var documentInteractionController: UIDocumentInteractionController = {
let vc = UIDocumentInteractionController()
vc.delegate = self
return vc
}()
func getSelf() -> TableViewController {
return self
}
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.names[indexPath.row].url)
}
func storeAndShare(withURL url: URL) {
let directoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
var newURL = directoryURL.appendingPathComponent(url.lastPathComponent)
var index = 1
let originalNewURL = newURL
while FileManager.default.fileExists(atPath: newURL.path) {
newURL = originalNewURL
let comp: NSString = newURL.lastPathComponent as NSString
newURL.deleteLastPathComponent()
let newName: String = "\(comp.deletingPathExtension) \(index).\(comp.pathExtension)"
newURL.appendPathComponent(newName)
index = index + 1
}
do {
try FileManager.default.copyItem(at: url, to: newURL)
DispatchQueue.main.async { [self] in
names.append(newURL.lastPathComponent)
tableView.insertRows(at: [IndexPath(row: names.count - 1, section: 0)], with: .automatic)
}
} catch {
print("ERROR: \(error).") // ERROR: Error Domain=NSCocoaErrorDomain Code=257 "The file “I am a file and you put documents in me.pdf” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/תיקיות/I am a file and you put documents in me.pdf, NSUnderlyingError=0x281ab2790 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}.
}
}
}
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
}
}
基本上,当用户添加新文件时,我的应用程序会尝试将其复制到文档文件夹中,以便将其存储在那里。
尝试将所选文件复制到文档文件夹时出现以下错误:
Error Domain=NSCocoaErrorDomain Code=257 "The file “I am a file and you put documents in me.pdf” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/תיקיות/I am a file and you put documents in me.pdf, NSUnderlyingError=0x281ab2790 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
我似乎没有查看该文件的权限。但这很奇怪,因为我刚刚使用 UIDocumentInteractionController
选择了文件,并且正如我之前所说,它在模拟器上运行良好。
如何获得复制文件的权限?提前致谢!
最佳答案
我也遇到了同样的问题,按照@Cameron的回答here ,
简而言之,您需要做的就是包装处理文件的代码部分,如下所示:
func readFile(url: URL){
// `url` to the directory or file you are trying to access.
url.startAccessingSecurityScopedResource()
// deal with your file here
url.stopAccessingSecurityScopedResource()
}
就您而言,应该是:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = names[indexPath.row]
// newly added
names[indexPath.row].url.startAccessingSecurityScopedResource()
if FileManager.default.fileExists(atPath: names[indexPath.row].url.path) {
cell.accessoryType = .disclosureIndicator
} else {
cell.accessoryType = .none
}
// newly added
names[indexPath.row].url.stopAccessingSecurityScopedResource()
return cell
}
关于ios - 尝试使用 FileManager 复制文件时出错 : Operation not permitted,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65413740/