5

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.

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.)

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.}

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.

enter image description here 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  

}  

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  

}  
4

5 回答 5

3

经过四五个小时的努力解决这个问题,我发现了一个简单的解决方案:不要在模拟器中测试。我切换到在我的设备上进行测试,一切都立即开始按照宣传的那样工作。

[我不能从这里的经验说话,但可能是“在模拟器中不起作用”的问题仅限于 Sierra,但模拟器确实在 High Sierra 中工作。这可以解释为什么有些用户会看到这个问题而其他用户却没有,尤其是为什么 Apple 在 WWDC 视频中似乎完全没有意识到这一点。]

于 2017-11-04T19:46:41.647 回答
2

当我尝试保存到NSTemporaryDirectory().

如果您改为保存到文档目录 ( [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]),它似乎可以正常工作!

更新:看起来这个问题在 iOS 11 beta 3 中已修复,您现在可以NSTemporaryDirectory()正确保存新创建的文档。

于 2017-06-29T16:10:46.503 回答
0

这是我目前的理论。

这个错误

Error Domain=NSFileProviderInternalErrorDomain Code=1 "The reader is not permitted to access the URL."

首次使用 -initWithFileURL 在新 URL 创建 UIDocument 时显示。它基本上是在说“这个 URL 还不存在”,但听起来更像是一个权限问题。

据我所知,它不会阻止您保存、打开、编辑或关闭文件。所以我认为这只是苹果应该采取的一个多余的错误。

于 2017-10-21T06:08:39.660 回答
0

我发现当LSSupportsOpeningDocumentsInPlaceinfo.plist 中的属性设置为 YES 时,模拟器上会发生错误。在我的情况下,将此属性设置为 NO,然后它开始工作。在真实设备上,它无论如何都可以正常工作而不会出错。

于 2018-03-01T11:50:16.027 回答
0

有类似的问题,并尝试了在方案设置中提供默认核心位置的方法,它现在可以工作了。此答案中提到了该方法:IOS 9 Error Domain=kCLErrorDomain Code=0 "(null)"

于 2018-06-05T22:53:16.180 回答