Search code examples
swiftcsvuidocumentpickerviewcontroller

FileManager returns url with Nil instead of file on it


User picks document from UIDocumentPickerViewController that i will be working with later. Document picker delegate calls and gives me url for file, but there is no file at all.

This is how i create documentPicker. I use supportedFiles because typing manually extension doesn't work for me

let supportedFiles: [UTType] = [UTType.data]
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: supportedFiles)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .fullScreen
present(documentPicker, animated: true, completion: nil)

There is documentPicker delegate with all checks

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {

        var path = urls.first!.path
        let stream = InputStream(url: URL(fileURLWithPath: path))
        print(path)
        print(FileManager.default.fileExists(atPath: path))

        do {
            let items = try FileManager.default.contentsOfDirectory(atPath: path)
            print(items.count)
            for item in items {
                print("Found (item)")
            }
        } catch {
            print(error)
        }

        do {
            let csv = try CSVReader(stream: stream!)
            print("Everything is ok")
            while let row = csv.next() {
                print(row)
            }
        } catch {
            print(error)
        }
    }

And console show me this

/private/var/mobile/Containers/Shared/AppGroup/3232A257-B8F6-4F39-A12B-A7192EBF9524/File Provider Storage/Games.csv
false
Error Domain=NSCocoaErrorDomain Code=256 "The file “Games.csv” couldn’t be opened." UserInfo={NSUserStringVariant=(
    Folder
), NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/3232A257-B8F6-4F39-A12B-A7192EBF9524/File Provider Storage/Games.csv, NSUnderlyingError=0x282a277e0 {Error Domain=NSPOSIXErrorDomain Code=20 "Not a directory"}}
cannotOpenFile

As i understand i got url for file that does not exists? Then why fileManager gives me an error that this file is not a directory instead of saying that there is nothing at this url? There was also an error that i dont have permission to read this file, so i changed it to be readable. That means that it can see it, but it can't? I just dont understand.

Also tried to change path by deleting /private but it didnt work

Update:

When trying to get list of items in folder in which Games.svc is located I get another error

Error Domain=NSCocoaErrorDomain Code=257 "The file “File Provider Storage” couldn’t be opened because you don’t have permission to view it." UserInfo={NSUserStringVariant=(
    Folder
), NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/3232A257-B8F6-4F39-A12B-A7192EBF9524/File Provider Storage/, NSUnderlyingError=0x2819254d0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

Solution

  • Found apple documentation about getting access to directories. Edited my code to this and now it is working

    guard urls.first!.startAccessingSecurityScopedResource() else {
         print("Error getting access")
         return
    }
    
    defer { urls.first!.stopAccessingSecurityScopedResource() }
    
    let path = urls.first!.path
    let stream = InputStream(url: URL(fileURLWithPath: path))
    
    do {
          let csv = try CSVReader(stream: stream!)
          print("Everything is ok")
          while let row = csv.next() {
          print(row)
    }
          URL(fileURLWithPath: path).stopAccessingSecurityScopedResource()
    } catch {
          print(error)
    }
    

    Basically before working with the URL you get the request to use secured URL by this function

    guard urls.first!.startAccessingSecurityScopedResource() else {
         print("Error getting access")
         return
    }
    
    defer { urls.first!.stopAccessingSecurityScopedResource() }
    

    And end working with secured connection by writing this line

    URL(fileURLWithPath: path).stopAccessingSecurityScopedResource()
    

    However code written in documentation is not working for me, and error check(that i deleted) still giving me an error

    Update

    If code is not working, you can delete this line

    defer { urls.first!.stopAccessingSecurityScopedResource() }