首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >保存UIDocument失败,权限错误-“`NSCocoaErrorDomain`‘代码`513’

保存UIDocument失败,权限错误-“`NSCocoaErrorDomain`‘代码`513’
EN

Stack Overflow用户
提问于 2021-01-08 22:48:44
回答 1查看 427关注 0票数 0

我正在尝试构建和iOS应用程序类似的页面/数字/基调。每个应用程序都是基于文档的应用程序,用户首先获得一个UIDocumentBrowserViewController,用户选择在应用程序中打开一个文档。例如,用户可以选择一个.numbers文件并打开它,或者用户可以选择一个.csv,然后将这个csv文件导入到一个数字文件中,该数字文件沿原始csv保存在同一位置。

在我的应用程序中,我希望用户选择一个.csv文件,然后将其导入自己的文档格式(称为.pivot),并将其与csv文件一起保存(就像数字一样)。这在模拟器中很好,但是当我在设备上运行我的代码时,在我的自定义数据透视文档上调用save(to:for:completionHandler:)时会出现一个错误。

我的文档浏览器代码如下。

代码语言:javascript
运行
复制
class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        delegate = self
        
        allowsDocumentCreation = false
        allowsPickingMultipleItems = false
    }
    
    func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) {
        guard let sourceURL = documentURLs.first else { return }
        
        if sourceURL.pathExtension == "csv" {
            
            // Create a CSV document so we can read the CSV data
            let csvDocument = CSVDocument(fileURL: sourceURL)
            csvDocument.open { _ in
                
                guard let csv = csvDocument.csvData else {
                    fatalError("CSV is nil upon open")
                }
                
                // Create the file at the same location as the csv, with the same name just a different extension
                var pivotURL = sourceURL.deletingLastPathComponent()
                let pivotFilename = sourceURL.lastPathComponent .replacingOccurrences(of: "csv", with: "pivot")
                pivotURL.appendPathComponent(pivotFilename, isDirectory: false)
                
                let model = PivotModel()
                model.csv = csv
                let document = PivotDocument(fileURL: pivotURL)
                document.model = model
                
                document.save(to: pivotURL, for: .forCreating, completionHandler: { success in
                    
                    // `success` is false here
                    
                    DispatchQueue.main.async {
                        self.performSegue(withIdentifier: "presentPivot", sender: self)
                    }
                })
            }
        }
    }
    
}

加载csv文件的第一个UIDocument子类如下所示。

代码语言:javascript
运行
复制
import SwiftCSV // This is pulled in using SPM and works as I expect, so is unlikely causing this problem 

class CSVDocument: UIDocument {
    
    var csvData: CSV?
    
    override func contents(forType typeName: String) throws -> Any {
        return Data()
    }
    
    override func load(fromContents contents: Any, ofType typeName: String?) throws {
        guard let data = contents as? Data else {
            fatalError("No file data")
        }
        
        guard let string = String(data: data, encoding: .utf8) else {
            fatalError("Cannot load data into string")
        }
        
        csvData = try CSV(string: string)
    }
}

我的定制数据透视文档的第二个UIDocument子类如下所示。通过重写handleError()函数,我可以看到保存失败,NSCocoaErrorDomain中有一个错误,代码为513

代码语言:javascript
运行
复制
class PivotDocument: UIDocument {
    
    var model: PivotModel!
    var url: URL!
    
    override func contents(forType typeName: String) throws -> Any {
        let encoder = JSONEncoder()
        return try encoder.encode(model)
    }
    
    override func load(fromContents contents: Any, ofType typeName: String?) throws {        
        guard let data = contents as? Data else {
            fatalError("File contents are not Data")
        }
        
        let decoder = JSONDecoder()
        model = try decoder.decode(PivotModel.self, from: data)
    }
    
    override func handleError(_ error: Error, userInteractionPermitted: Bool) {
        let theError = error as NSError
        
        print("\(theError.code)") // 513
        print("\(theError.domain)") // NSCocoaErrorDomain
        print("\(theError.localizedDescription)") // “example.pivot” couldn’t be moved because you don’t have permission to access “CSVs”.
        
        super.handleError(error, userInteractionPermitted: userInteractionPermitted)
    }
}

这在模拟器(我的用户可以访问所有文件系统)中工作,但在iOS (用户和应用程序的权限不同)上不起作用,这让我觉得我有权限问题。例如,我是否需要在我的Xcode项目中声明一些权利?

还是我只是误用了UIDocument API,是否需要找到不同的实现?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-11 21:43:26

我找到了我想要的函数,它可以复制iWork应用程序的功能!

UIDocumentBrowserViewController有这个函数importDocument(at:nextToDocumentAt:mode:completionHandler:)。从医生那里:

使用此方法将文档导入到与现有文档相同的文件提供程序和目录中。例如,要复制已经由文件提供程序管理的文档:在用户的临时目录中创建原始文件的副本。一定要给它一个独特的名字。调用importDocument(at:nextToDocumentAt:mode:completionHandler:),,传入临时文件的URL作为documentURL参数,原始文件的URL作为neighborURL参数。

因此,documentBrowser(_:didPickDocumentsAt:)现在是:

代码语言:javascript
运行
复制
let pivotFilename = sourceURL.lastPathComponent .replacingOccurrences(of: "csv", with: "pivot")

let path = FileManager.default.temporaryDirectory.appendingPathComponent(pivotFilename)
if FileManager.default.createFile(atPath: path.path, contents: nil, attributes: nil) {
    
    self.importDocument(at: path, nextToDocumentAt: sourceURL, mode: .copy) { (importedURL, errorOrNil) in
        guard let pivotURL = importedURL else {
            fatalError("No URL for imported document. Error: \n \(errorOrNil?.localizedDescription ?? "NO ERROR")")
        }
    
        
        let model = PivotModel()
        model.csv = csv
        let document = PivotDocument(fileURL: pivotURL)
        document.model = model
        
        DispatchQueue.main.async {
            self.performSegue(withIdentifier: "presentPivot", sender: self)
        }
    }
}
else {
    fatalError("Could not create local pivot file in temp dir")
}

没有权限错误。希望这对将来的其他人有帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65637412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档