user2129800
user2129800

Reputation: 151

How to find the error description from an NSError code?

I'm trying to find an easier/more reliable way to figure out an NSError's localized description from its error code than Google searching it.

For example, I know that NSURLErrorDomain code -1003 corresponds to "A server with the specified hostname could not be found". But if I try to verify it in code it doesn't match.

let error = NSError(domain: "NSURLErrorDomain", code: -1003)
print(error.localizedDescription)
// "The operation couldn’t be completed. (NSURLErrorDomain error -1003.)"

Looking up -1003 in documentation also doesn't match: "The host name for a URL couldn’t be resolved."

So I am looking for a way to figure out descriptions from an error code with a function, or the documentation that has the description I expected. I was hoping there'd be a function similar to HTTPURLResponse.localizedString(forStatusCode:)

Upvotes: 4

Views: 5431

Answers (4)

S1LENT WARRIOR
S1LENT WARRIOR

Reputation: 12224

you can have following extension to URLError.Code for getting a readable reason from URLError.Code.

extension URLError.Code: CustomDebugStringConvertible {
    public var debugDescription: String {
        switch self {
        case .unknown:
            "URLError.Code.unknown: \(rawValue)"
        case .cancelled:
            "URLError.Code.cancelled: \(rawValue)"
        case .badURL:
            "URLError.Code.badURL: \(rawValue)"
        case .timedOut:
            "URLError.Code.timedOut: \(rawValue)"
        case .unsupportedURL:
            "URLError.Code.unsupportedURL: \(rawValue)"
        case .cannotFindHost:
            "URLError.Code.cannotFindHost: \(rawValue)"
        case .cannotConnectToHost:
            "URLError.Code.cannotConnectToHost: \(rawValue)"
        case .networkConnectionLost:
            "URLError.Code.networkConnectionLost: \(rawValue)"
        case .dnsLookupFailed:
            "URLError.Code.dnsLookupFailed: \(rawValue)"
        case .httpTooManyRedirects:
            "URLError.Code.httpTooManyRedirects: \(rawValue)"
        case .resourceUnavailable:
            "URLError.Code.resourceUnavailable: \(rawValue)"
        case .notConnectedToInternet:
            "URLError.Code.notConnectedToInternet: \(rawValue)"
        case .redirectToNonExistentLocation:
            "URLError.Code.redirectToNonExistentLocation: \(rawValue)"
        case .badServerResponse:
            "URLError.Code.badServerResponse: \(rawValue)"
        case .userCancelledAuthentication:
            "URLError.Code.userCancelledAuthentication: \(rawValue)"
        case .userAuthenticationRequired:
            "URLError.Code.userAuthenticationRequired: \(rawValue)"
        case .zeroByteResource:
            "URLError.Code.zeroByteResource: \(rawValue)"
        case .cannotDecodeRawData:
            "URLError.Code.cannotDecodeRawData: \(rawValue)"
        case .cannotDecodeContentData:
            "URLError.Code.cannotDecodeContentData: \(rawValue)"
        case .cannotParseResponse:
            "URLError.Code.cannotParseResponse: \(rawValue)"
        case .appTransportSecurityRequiresSecureConnection:
            "URLError.Code.appTransportSecurityRequiresSecureConnection: \(rawValue)"
        case .fileDoesNotExist:
            "URLError.Code.fileDoesNotExist: \(rawValue)"
        case .fileIsDirectory:
            "URLError.Code.fileIsDirectory: \(rawValue)"
        case .noPermissionsToReadFile:
            "URLError.Code.noPermissionsToReadFile: \(rawValue)"
        case .dataLengthExceedsMaximum:
            "URLError.Code.dataLengthExceedsMaximum: \(rawValue)"
        case .secureConnectionFailed:
            "URLError.Code.secureConnectionFailed: \(rawValue)"
        case .serverCertificateHasBadDate:
            "URLError.Code.serverCertificateHasBadDate: \(rawValue)"
        case .serverCertificateUntrusted:
            "URLError.Code.serverCertificateUntrusted: \(rawValue)"
        case .serverCertificateHasUnknownRoot:
            "URLError.Code.serverCertificateHasUnknownRoot: \(rawValue)"
        case .serverCertificateNotYetValid:
            "URLError.Code.serverCertificateNotYetValid: \(rawValue)"
        case .clientCertificateRejected:
            "URLError.Code.clientCertificateRejected: \(rawValue)"
        case .clientCertificateRequired:
            "URLError.Code.clientCertificateRequired: \(rawValue)"
        case .cannotLoadFromNetwork:
            "URLError.Code.cannotLoadFromNetwork: \(rawValue)"
        case .cannotCreateFile:
            "URLError.Code.cannotCreateFile: \(rawValue)"
        case .cannotOpenFile:
            "URLError.Code.cannotOpenFile: \(rawValue)"
        case .cannotCloseFile:
            "URLError.Code.cannotCloseFile: \(rawValue)"
        case .cannotWriteToFile:
            "URLError.Code.cannotWriteToFile: \(rawValue)"
        case .cannotRemoveFile:
            "URLError.Code.cannotRemoveFile: \(rawValue)"
        case .cannotMoveFile:
            "URLError.Code.cannotMoveFile: \(rawValue)"
        case .downloadDecodingFailedMidStream:
            "URLError.Code.downloadDecodingFailedMidStream: \(rawValue)"
        case .downloadDecodingFailedToComplete:
            "URLError.Code.downloadDecodingFailedToComplete: \(rawValue)"
        case .internationalRoamingOff:
            "URLError.Code.internationalRoamingOff: \(rawValue)"
        case .callIsActive:
            "URLError.Code.callIsActive: \(rawValue)"
        case .dataNotAllowed:
            "URLError.Code.dataNotAllowed: \(rawValue)"
        case .requestBodyStreamExhausted:
            "URLError.Code.requestBodyStreamExhausted: \(rawValue)"
        case .backgroundSessionRequiresSharedContainer:
            "URLError.Code.backgroundSessionRequiresSharedContainer: \(rawValue)"
        case .backgroundSessionInUseByAnotherProcess:
            "URLError.Code.backgroundSessionInUseByAnotherProcess: \(rawValue)"
        case .backgroundSessionWasDisconnected:
            "URLError.Code.backgroundSessionWasDisconnected: \(rawValue)"
        default:
            "URLError.Code.unknownError: \(rawValue)"
        }
    }
}

Hope this helps.

Upvotes: 0

MarkMendy
MarkMendy

Reputation: 41

Folks, I wanted to include this link for others to reference as they are trying to identify a particular Error Code number. Error Codes provided by the Swift.org open source project on GitHub

Upvotes: 0

Rob
Rob

Reputation: 438122

When you create your own NSError object like that, that localizedDescription is not generated for you. When URLSession generates error objects, though, the localized description is populated:

let url = URL(string: "https://bad.domain")!
URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error as? URLError {
        print(error.localizedDescription)  // “A server with the specified hostname could not be found.”
    }
}.resume()

So, if you have an error and want to see the localized description, just do that. It simply will not work if you create your own NSError object manually.

But generally, we wouldn't worry about the localized description and, instead, test for various code values of URLError, looking for a code of .cannotFindHost:

let url = URL(string: "https://bad.domain")!
URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error as? URLError {
        switch error.code {
        case .cannotFindHost: print("cannotFindHost")
        case .cancelled:      print("cancelled")
        case .badURL:         print("badURL")
        // ...
        default:              break
        }
    }
}.resume()

Or, alternatively, you can search for the old NSURLError code values using NSError, too, looking for NSURLErrorCannotFindHost:

URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error as NSError? {
        switch error.code {
        case NSURLErrorCannotFindHost: print("cannotFindHost")
        case NSURLErrorCancelled:      print("cancelled")
        case NSURLErrorBadURL:         print("badURL")
        // ...
        default:                       break
        }
    }
}.resume()

You can also “quick open” by pressing shift-command-O (the letter “Oh”), search for NSURLError, uncheck the “Swift” button in the upper right corner of the quick open dialog:

enter image description here

When you open up the NSURLError.h file, you can then see all the codes listed there.

But, no, just by creating a NSError with the specified domain and code, the localizedDescription isn't magically populated for you. URLSession creates the proper error objects with descriptions, though.

Upvotes: 7

Rob Napier
Rob Napier

Reputation: 299565

No, there's no automatic lookup for most things (there is for Security errors using SecCopyErrorMessageString, but not generally). You have to check the headers. This is in NSURLError.h:

NSURLErrorCannotFindHost =          -1003,

Generally the string you're looking for will be in the NSError's userInfo, and is placed there by the thing that generates the error. It doesn't get looked up from the code. When there's no message in the userInfo, then the default for localizedDescription is to write "The operation couldn't be completed..."

I don't believe there's any built-in way to generate an error "like the system would have." (This would be very subsystem dependent, since URLErrors have lots of keys to fill in that don't apply to other kinds of errors.)

Upvotes: 2

Related Questions