11

Since iOS 11 I have encountered the following error every time I am creating a new document using UIDocument API:

[ERROR] Could not get attribute values for item /var/mobile/Containers/Data/Application/XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX/Documents/myDoc-XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX.myFile (n).

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

Unlike similar questions (1, 2, 3) on SO on this, I am not using UIDocumentBrowserViewController. I am simply creating a UIDocument and call save() to the Documents directory myself. The closest question I found uses UIManagedDocument. However, in my case, the file is still created and written successfully despite the error message.

Here's the gist of my save routine:

@IBAction func createDoc(_ sender: Any) {
    let uuid = UUID().uuidString
    let doc = Document(baseName: "myDoc-\(uuid)")
    doc.save(to: doc.fileURL, for: .forCreating) { (completed) in
        if (completed) {
            doc.close(completionHandler: nil)
            self.verifyNumberOfFiles()
        }
    }
}

My UIDocument subclass is also almost blank for simplicity of this question:

class Document: UIDocument {    
    
    let fileExtension = "myFile"
    
    override init(fileURL url: URL) {
        super.init(fileURL: url)
    }

    /// Convenience method for `init(fileURL:)`
    convenience init(baseName: String) {
        self.init(fileURL: documentsDirectory.appendingPathComponent(baseName).appendingPathExtension(Document.fileExtension))
    }
    
    override func contents(forType typeName: String) throws -> Any {
        return NSData()
    }
    
    override func load(fromContents contents: Any, ofType typeName: String?) throws {
        
    }
    
}

I'm always writing to Documents folder, and my lookup routine can verify that my files are successfully created:

public var documentsDirectory: URL {
    return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
}

func loadFileURLs(from dirURL: URL) -> [URL]? {
    return try? FileManager().contentsOfDirectory(at: dirURL, includingPropertiesForKeys: nil)
}

What I have discovered so far:

  • The error appears even when I set up my UTI already. See this and this.
  • I can verify that my UTI works when I send a "myFile" to my device over AirDrop and it correctly triggers my app to open.
  • The error appears on iOS 11 only. The same code doesn't reproduce the error on iOS 10, like in the question above.
  • I tried adding UISupportsDocumentBrowser key although I'm not using the browser but it's not dissolve the error.

What is happening? Is this just a "noise" error message on iOS 11?

Here's my GitHub code online if anyone is interested.

Community
  • 1
  • 1
HuaTham
  • 7,486
  • 5
  • 31
  • 50
  • I came across this as well and would love to know about a proper fix for this. In the mean-time, my workaround is to first create the file and then use the usual way of opening an existing `UIDcument`: In `createDoc` first get the data for an empty document, call `try data.write(to: url)` and then initialise the `UIDocument` subclass and call `open` on it. – Adrian Schönig Feb 12 '18 at 08:53
  • Also note that in my case the document was *not* created when the error popped up that you describe here, so it wasn't just a "noise" error. – Adrian Schönig Feb 12 '18 at 08:54
  • @AdrianSchönig can you post some code in the answer section? Although it's not the "correct" answer, it'd add to the discussion. Thanks. – HuaTham Feb 12 '18 at 11:55
  • 1
    Same problem here. Error logged, but document is created. – Mark Feb 14 '18 at 12:09
  • I tested this in an iOS 11.3 simulator: the same error is still logged, but the document is created (as reported by @Mark above). – Paulo Mattos Apr 14 '18 at 14:16

2 Answers2

4

A workaround for this is to create the file by saving its data to the disk, and then open it as you would with an existing file.

Your createDoc(_:) method would then like this:

@IBAction func createDoc(_ sender: Any) {
  let uuid = UUID().uuidString
  let baseName = "myDoc-\(uuid)"
  let url = documentsDirectory
      .appendingPathComponent(baseName)
      .appendingPathExtension(Document.fileExtension)

  do {
    let emptyFileData = Data()
    try emptyFileData.write(to: url)
    let document = Document(fileURL: url)
    document.open() { completed in
      guard completed else { 
        // handle error
        return 
      }
      doc.close(completionHandler: nil)
      self.verifyNumberOfFiles() 
    }
  } catch {
    // handle error
  }
}
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Adrian Schönig
  • 1,786
  • 18
  • 26
0

In Xcode 9.3 it is possible to specify a new item in info.plist:

Supports Document Browser (YES)

This enables access to the application's documents directory (for example, /var/mobile/Containers/Data/Application/3C21358B-9E7F-4AA8-85A6-A8B901E028F5/Documents on a device). Apple Developer doc here.

paul.lander
  • 458
  • 4
  • 5