16

I have Googled and poked around Stack Overflow and can't seem to find a solution for this. I have:

let fileURL = URL( string: "file:///Users/me/file.txt" )    
var rawDataString: String 
var errorString: String?

do {
    rawDataString = try String( contentsOf: fileURL!, encoding: String.Encoding.utf8 )
} catch let error as NSError {
    errorString = error.description
    print( errorString! )
    return
}

and it's erroring out with

Error Domain=NSCocoaErrorDomain Code=257 "The file “file.txt” couldn’t be opened because you don’t have permission to view it."

Permissions are read for all users:

$ ls -al file.txt
-rw-r--r--@ 1 me  staff  348306 Dec 13  2016 file.txt

Any ideas would be most welcome.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Dribbler
  • 4,343
  • 10
  • 33
  • 53
  • 4
    You need to turn off App Sandbox in your app target capabilities. Another option is present `NSOpenPanel` to let the user select the file. – Leo Dabus Mar 01 '18 at 16:37
  • 1
    Btw not related to your question but `String.Encoding` is redundant (inferred) and no need to cast the error to NSError `encoding: .utf8 )` and `} catch { print(error)` – Leo Dabus Mar 01 '18 at 16:41
  • @LeoDabus I'm not seeing where to turn off App Sandbox in my scheme. Can you point me to it? – Dribbler Mar 01 '18 at 16:44
  • 1
    You can also use `URL` fileURLWithPath initializer. You just need to drop the url scheme file://. `let fileURL = URL(fileURLWithPath: "/Users/me/file.txt" )` – Leo Dabus Mar 01 '18 at 16:44
  • 1
    https://www.dropbox.com/s/19pgzpmtgr4a4t6/Screen%20Shot%202018-03-01%20at%2013.44.27.png?dl=1 – Leo Dabus Mar 01 '18 at 16:45
  • 2
    you can also drop the txt file into your project and include it into your Bundle – Leo Dabus Mar 01 '18 at 16:48
  • @LeoDabus fileURLWithPath works beautifully, but I'm not sure about not casting the error to NSError--if I just do } catch let error { it gives Value of type 'Error' has no member 'description' – Dribbler Mar 01 '18 at 17:02
  • 1
    Just print(error) you can add localizedDescription but it is redundant – Leo Dabus Mar 01 '18 at 17:12

4 Answers4

21

(For iOS)

Sadly @Dribbler´s answer didn't work for me because I didn't have App Sandbox enabled and it still didn't work. In my case I used the UIDocumentPickerViewController and I was unable to access the file.

Adding url.startAccessingSecurityScopedResource() before working with the file resolved the issue for me.

Here is an example of the didPickDocumentsAt delegate function from a UIDocumentPickerViewController:

guard let url = urls.first else {
      return
}
guard url.startAccessingSecurityScopedResource() else { // Notice this line right here
     return
}
    
do {
    let data = try Data(contentsOf: url)
} catch let error {
    print(error.localizedDescription)
}

After adding that line it worked for me.

Oscar Junius
  • 320
  • 3
  • 10
20

Anyone coming across this thread, @LeoDabus pointed me to where to turn off sandbox, which worked:

enter image description here

He also cleaned up my code a bit:

let fileURL = URL( fileURLWithPath: "/Users/me/file.txt" )    
var rawDataString: String
var errorString: String?

do {
    rawDataString = try String( contentsOf: fileURL, encoding: .utf8 )
} catch let error as NSError {
    errorString = error.description
    rawDataString = ""
    return
}
Dribbler
  • 4,343
  • 10
  • 33
  • 53
  • Turning off App Sandbox wasn't an option available to me. App Sandbox wasn't even listed. Are there other causes for this? – ScottyBlades May 24 '18 at 18:55
  • That's odd @ScottyBlades--I just checked it for a project that I'm working on, and it's definitely there. If you click on the project name in the file selector window, the one on top of the tree with all your files, then you get a window with tabs General, Capabilities, Resource Tags, etc., and if you click on Capabilities, App Sandbox is up at the top. I'm using Xcode 9.3.1. Hope this helps. – Dribbler May 24 '18 at 22:40
  • Yea...in my project running Xcode 9.2 after clicking my project in the file navigator, targets my project, capabilities I see [iCloud, Push Notifications, Game Center, Wallet, Siri, Apple Pay, in-app purchases, maps, personal vpn, network extensions, hotspot configuration, multipath, near field communication tag reading etc. etc. etc. no sandbox. – ScottyBlades May 24 '18 at 23:49
  • 7
    Are you building for iOS? This is for a Mac app – Dribbler May 25 '18 at 00:42
5

I actually was not able to get the preferred answers above to work for me in swift playground.

Another solution is just to create a command line app in Xcode. Then paste the above and it should work fine.

coletrain
  • 2,809
  • 35
  • 43
1

Solution According to Apple Docs https://developer.apple.com/documentation/foundation/url/1779698-startaccessingsecurityscopedreso

extension ViewController : UIDocumentPickerDelegate{

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

    guard let url = urls.first else {return}

    if url.startAccessingSecurityScopedResource(){

        if let data = try? Data(contentsOf: url){
            let filename = url.lastPathComponent
 
            print("Data Byte",data)
            print("filename",filename)
        }
        
        url.stopAccessingSecurityScopedResource()
    }

}

}

Zain Ahmed
  • 179
  • 2
  • 3