19

I am using NSFileManager.contentsOfDirectoryAtPath to get an array of file names in a directory. I want to use the new do-try-catch syntax to handle the errors:

do {
    
    let docsArray = try fileManager.contentsOfDirectoryAtPath(docsPath)

} catch {
    
    // handle errors
    print(error) // this is the best I can currently do

}

I can imaging that an error might be that the docsPath doesn't exist, but I don't know how to catch this error. And I don't know what other possible errors might occur.

Documentation example

The Error Handling documentation has an example like this

enum VendingMachineError: ErrorType {
    case InvalidSelection
    case InsufficientFunds(centsNeeded: Int)
    case OutOfStock
}

and

do {
    try vend(itemNamed: "Candy Bar")
    // Enjoy delicious snack
} catch VendingMachineError.InvalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.OutOfStock {
    print("Out of Stock.")
} catch VendingMachineError.InsufficientFunds(let amountNeeded) {
    print("Insufficient funds. Please insert an additional \(amountNeeded) cents.")
}

but I don't know how to do something similar for catching the errors of the standard Swift types that have methods using the throws keyword.

The NSFileManager class reference for contentsOfDirectoryAtPath doesn't say what kind of errors might be returned. So I don't know what errors to catch or how to handle them if I get them.

Update

I would like to do something like this:

do {
    let docsArray = try fileManager.contentsOfDirectoryAtPath(docsPath)
} catch FileManagerError.PathNotFound {
    print("The path you selected does not exist.")
} catch FileManagerError.PermissionDenied {
    print("You do not have permission to access this directory.")
} catch ErrorType {
    print("An error occured.")
}
Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 4
    Duplicate? [How get the list of errors thrown by a function?](http://stackoverflow.com/q/34877027/2415822) – JAL Mar 23 '16 at 20:39
  • @JAL, Yes, that question is similar. In your answer there you showed how to get the `NSError`, but you didn't give any details about how to differentiate and handle different types of errors. – Suragch Mar 24 '16 at 13:21
  • Also related (see the discussion in the comments): [Find what errors a function can throw in Xcode with Swift](http://stackoverflow.com/q/36139221/2415822) There's really no way to get a list of `ErrorType`s thrown by a function. `ErrorType` is a protocol that objects an enums can conform to (`NSError` conforms to `ErrorType`, and you need to check the error code returned to handle specific errors). – JAL Mar 24 '16 at 14:08

3 Answers3

17

NSError automatically bridges to ErrorType where the domain becomes the type (e.g. NSCocoaErrorDomain becomes CocoaError) and the error code becomes the value (NSFileReadNoSuchFileError becomes .fileNoSuchFile)

import Foundation

let docsPath = "/file/not/found"
let fileManager = FileManager()

do {
    let docsArray = try fileManager.contentsOfDirectoryAtPath(docsPath)
} catch CocoaError.fileNoSuchFile {
    print("No such file")
} catch let error {
    // other errors
    print(error.localizedDescription)
}

As for knowing which error can be returned by a specific call, only the documentation can help. Almost all Foundation errors are part of the CocoaError domain and can be found in FoundationErrors.h (though there are some rare bugs where Foundation can also sometimes return POSIX errors under NSPOSIXErrorDomain) but these ones might not have been fully bridged so you will have to fall back on managing them at the NSError level.

More information can be found in « Using Swift with Cocoa and Objective-C (Swift 2.2) »

Axel Guilmin
  • 11,454
  • 9
  • 54
  • 64
Julien
  • 3,427
  • 20
  • 22
  • 1
    For Swift 3+, you can do: catch CocoaError.fileReadNoSuchFile { ... } A list of catchable CocoaErrors is at https://developer.apple.com/documentation/foundation/cocoaerror – biomiker Jun 27 '18 at 19:59
3

It will return NSError:

let fileManager = NSFileManager()

do {

    let docsArray = try fileManager.contentsOfDirectoryAtPath("/")

} catch let error as NSError {

    // handle errors
    print(error.localizedDescription)

    // The file “Macintosh HD” couldn’t be opened because you don’t have permission to view it.
}
MirekE
  • 11,515
  • 5
  • 35
  • 28
  • So you are saying that there is not an enum list like in the Error Handling docs for custom classes? I should just print whatever description the error gives me and not try to have individualized behavior based on the error type? What if I want to do something besides just printing the error? – Suragch Aug 13 '15 at 01:48
  • 1
    Right. This is still the same thing as you see in Obj-C and if you look at the Obj-C documentation, it uses NSError, which is pretty much consistent with the rest of the Cocoa (Touch) framework. NSError is a class that conforms to ErrorType. You can do more than just print a description, see at https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/index.html. – MirekE Aug 13 '15 at 01:57
  • Is there a way to do anything like what I showed in my update? – Suragch Aug 13 '15 at 02:31
0

What your'e asking in the "update" part is not possible. It's the throwing function decision to let you know what it's may throw, or not to show it, and then you need to handle a generic error.

A lot of functions do reveal information about the thrown errors - for example:

func startVPNTunnel() throws
Description 
Start the process of connecting the VPN
true if the process of connecting the VPN started successfully, false if an error occurred.
Parameters  
error   
A pointer to a pointer to an NSError object. If specified and the VPN connection process cannot be started due to an error, this parameter will be set to point to an NSError object containing details about the error. See NEVPNManager Class Reference for a list of possible errors.

Edit: a possible reason for this - that's way, the throwing function can change the errors it's throws, and all the code that catch those error would still be valid.

Witterquick
  • 6,048
  • 3
  • 26
  • 50