Having Trouble Getting the UIDocumentBrowserController to open docs in a Document based app
Asked Answered
D

5

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  

}  
Danieladaniele answered 21/6, 2017 at 2:35 Comment(3)
Did you ever manage to solve it? :/Seismograph
Is there are bug report for this?Knecht
I've filed a bug report. #35033364Knecht
C
3

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.

[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.]

Candiot answered 4/11, 2017 at 19:46 Comment(5)
Out of curiosity, what version of OSX were you running? This problem went away for me when I went to high Sierra on the Mac.Danieladaniele
@StevenHovater Nice to hear from you - I'm using Sierra, and I too had come to the conclusion based on stuff said on the developer forums that the Simulator issue might be confined to Sierra. So thanks for this confirmation. I'll add that to my answer, but I can't speak from experience and I'll say so. I wonder whether the whole thing actually has to do with APFS? Obviously Sierra would lack that.Candiot
Thank you for saving me from banging my head at this problem for four or five hours!Delorsedelos
Exactly my situation too!Ruzich
I have the same bug on the device, did someone managed to (really) solve it?Metathesis
O
2

I had exactly the same issue when I was trying to save to NSTemporaryDirectory().

If you instead save to the documents directory ([[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]), it appears to work fine!

Update: it looks like this issue is fixed in iOS 11 beta 3, and you can now save newly created documents to NSTemporaryDirectory() correctly.

Outrage answered 29/6, 2017 at 16:10 Comment(1)
It continues to not work for me on iOS11 beta 3. I'm also using a file package, so it's possible that has something to do with it.Knecht
K
0

Here is my current theory.

This error

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

shows up when first creating a UIDocument at a new URL using -initWithFileURL. It's basically saying "this URL doesn't exist yet," but in a way that makes it sound more like a permissions issue.

As far as I can tell, it doesn't prevent you from saving, opening, editing, or closing the file. So I think it's just a superfluous error that Apple should have taken out.

Knecht answered 21/10, 2017 at 6:8 Comment(0)
E
0

I found that the error happens on simulator when LSSupportsOpeningDocumentsInPlace property is set to YES in the info.plist. Turn this property to NO, then it starts working, in my case. On the real device, it works anyway without having error.

Execute answered 1/3, 2018 at 11:50 Comment(0)
G
0

Had similar problem, and tried the method for providing a default Core Location in the Schemes settings and it works now. The method was mentioned in this answer: IOS 9 Error Domain=kCLErrorDomain Code=0 "(null)"

Gybe answered 5/6, 2018 at 22:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.