无法获取UIDocumentBrowserController来在基于文档的应用程序中打开文档

问题描述:

我一直在开发一个新的基于文档的应用程序,并且对新的UIDocumentBrowserController感到非常高兴...试图为文档浏览器UI推出自己的解决方案非常棘手!

I've been working on a new Document-based app, and was super glad about the new UIDocumentBrowserController...trying to roll my own solution for the document browser UI was tricky!

创建文档后,浏览器无法打开它.

I'm having some trouble getting the browser to open documents after they've been created.

现在发生的是,当我选择在文档浏览器中创建新文档时,尽管记录了一条错误消息,但仍按预期方式创建并打开了该文档.但是,关闭文档后,即使显示了文档,我也无法立即或在随后的启动时重新打开该文件.但是,这里有一个奇怪的提示,如果我在创建文档后停止运行该应用程序,但没有向其中添加新信息(触发了保存周期),然后再次运行该项目,则可以正确打开该文件.这让我觉得保存文件的方式有些问题. (注意:在此阶段,在继续执行icloud实施之前,我正在努力使本地,非/icloud实施工作正常进行.)

What happens now is that when I choose to create a new document in the document browser, the document is created and opened as expected, although an error message is logged. However, after the doc is closed, I cannot reopen the file, either immediately or upon subsequent launches, even though the document is displayed. However, a weird clue here is that if I stop running the app after creating the document, but without adding new information to it (triggering the save cycle), and run the project again, I can open the file correctly. Whuch makes me think that there's something in the way the files are being saved that is the issue. (Note: At this phase, I'm working on getting the local, non/icloud implentation working, before I move on to the icloud implementation.)

在将文档保存到磁盘时(或至少在大多数情况下!),这是代码中任何时候的错误消息: 2017-06-20 13:21:58.254938-0500讲道设计2 iOS [22454:5000138] [默认] [错误]无法获取项目文件的属性值:///Users/stevenhovater/Library/Developer/CoreSimulator/Devices/9A4364F2-B3A1-4AD9-B680-FB4BC876C707/data/容器/数据/应用程序/DD534ED8-C4A3-40FE-9777-AED961976878/Documents/Untitled-9.sermon.错误:错误Domain = NSFileProviderInternalErrorDomain代码= 1不允许阅读器访问URL." UserInfo = {NSLocalizedDescription =不允许读者访问URL.}

Here is the error message at any point in the code whenthe document is saved to disk (or at least most of the time!): 2017-06-20 13:21:58.254938-0500 Sermon Design 2 iOS[22454:5000138] [default] [ERROR] Could not get attribute values for item file:///Users/stevenhovater/Library/Developer/CoreSimulator/Devices/9A4364F2-B3A1-4AD9-B680-FB4BC876C707/data/Containers/Data/Application/DD534ED8-C4A3-40FE-9777-AED961976878/Documents/Untitled-9.sermon. Error: Error Domain=NSFileProviderInternalErrorDomain Code=1 "The reader is not permitted to access the URL." UserInfo={NSLocalizedDescription=The reader is not permitted to access the URL.}

我怀疑问题出在我的文档类型列表中,我试图通过模仿wwdc 2017 session 229的视频中的设置来进行设置.

I suspect that the issue lies somewher in my document types plists, which I've tried to set up by imitating the setup in the video for wwdc 2017 session 229.

我的文档被NSData对象封装,使用我认为是UIDocument的相当标准的子类实现. (我省略了生成缩略图的代码)

My docs are encapuslated by an NSData object, using what I take to be a pretty standard subclass implentation of UIDocument. (I'm omitting the code to generate the thumbnails)

override func contents(forType typeName: String) throws -> Any {  

    print("Saving Document Changes")  
    if sermon != nil {  
        let newData = NSKeyedArchiver.archivedData(withRootObject: sermon!)  

        return newData  
    } else {   
        let newData = NSKeyedArchiver.archivedData(withRootObject: Sermon())  

        return newData       
    }  
}  

override func fileAttributesToWrite(to url: URL, for saveOperation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] {  

    let thumbnail:UIImage = self.createThumbnail()       

    let thumbnaildict = [URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey : thumbnail]  
    let dict = [URLResourceKey.thumbnailDictionaryKey:thumbnaildict]  
   return dict        
}  

override func load(fromContents contents: Any, ofType typeName: String?) throws {  

    guard let newSermon:Sermon = NSKeyedUnarchiver.unarchiveObject(with: contents as! Data) as? Sermon else{  
        throw documentErrors.invalidFile  
    }  

    self.sermon = newSermon  

}  

在我的UIDocumentBrowserViewController子类中,这是获取本地文件名和创建新文档的代码.

In my subclass of UIDocumentBrowserViewController, Here is my code for getting a local filename and for creating the new document.

func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {  
    var newDocumentURL: URL? = nil  

        print("creating new local document")  

        guard let target  = self.newLocalFilename() else {  
            return  
        }  
        let targetSuffix = target.lastPathComponent  
        let tempURL = URL(fileURLWithPath: NSTemporaryDirectory() + targetSuffix)  

        let newDocument:SDDocument = SDDocument(fileURL: tempURL)  

        newDocument.sermon = Sermon()  

        /  
        newDocument.save(to: tempURL, for: .forCreating) { (saveSuccess) in  

            /  
            guard saveSuccess else {  
                /  
                importHandler(nil, .none)  
                return  
            }  

            /  
            newDocument.close(completionHandler: { (closeSuccess) in  

                /  
                guard closeSuccess else {  
                    /  
                    importHandler(nil, .none)  
                    return  
                }  

                /  
                importHandler(tempURL, .move)  
            })  
        }  

}  

func newLocalFilename() -> URL? {  
    let fileManager = FileManager()  

    guard let baseURL = self.localDocumentsDirectoryURL.appendingPathComponent("Untitled")  

        else {return nil}  

    var target = baseURL.appendingPathExtension(DocumentBrowserViewController.documentExtension)  

    var nameSuffix = 2  

    while fileManager.fileExists(atPath: target.path) {  
        target = URL(fileURLWithPath: baseURL.path + "-\(nameSuffix).\(DocumentBrowserViewController.documentExtension)")  

        nameSuffix += 1  
    }  
    let targetSuffix = target.lastPathComponent  
    print("Target name: \(targetSuffix)")  
    print("new url: \(target)")  

    return target  

}  

经过四个或五个小时的工作使我为解决这个问题而烦恼,我发现了一个简单的解决方案:不要在模拟器中进行测试.我切换到设备上的测试后,立即一切都按广告中的要求开始工作.

After four or five hours of work banging my head against this problem, I discovered a simple solution: don't test in the Simulator. I switched to testing on my device and instantly everything started working as advertised.

[我在这里不能从经验谈起,但可能是在Simulator中不起作用"问题仅限于Sierra,而Simulator确实在High Sierra中起作用.这可以解释为什么有些用户看到此问题而另一些用户看不到,尤其是为什么苹果公司似乎很高兴在WWDC视频中没有意识到这一点.]

[I can't speak from experience here, but it may be that the "doesn't work in the Simulator" problem is confined to Sierra, but that the Simulator does work in High Sierra. This would explain why some users see this issue and others don't, and especially why Apple seems blissfully unaware of it in the WWDC video.]