Search code examples
iosswiftenumscasting

Cast value to enum that inherits from Error


I have a service class that offers several methods that make calls to the backend, and a common theme for those methods is that I can pass callbacks for the success and error cases:

func makeCall(onSuccess: @escaping APIResponse, onError: @escaping APIError)

The type APIError is defined like so:

typealias APIError = (Error) -> Void

Furthermore I have an enum APICallError like this:

enum APICallError: Error {

    case insufficientCredentials
    case malformedResponse
    case forbidden

}

So in my service methods I can call onError(response.result.error!) if the result contained an error object (the force unwrap is just for brevity, I'm not really doing that) and also pass my own enum value if the HTTP result is not specific enough, like onError(APICallError.insufficientCredentials).

This works fine.

The problem is, I can't figure out how to evaluate in my client code whether the error parameter that's coming in is of type APICallError and which one of those specifically. If I do:

if let callError = error as? APICallError {
    if callError == .forbidden {
        // ...
    }
}

execution doesn't make it past the typecast. if error is APICallError also does not seem to work.

How can I cast the error parameter to my APICallError enum value that I know is in there, because when I print(error) it gives me myapp.APICallError.forbidden?


Solution

  • I tried to simulate what you have posted in your question in Playground, and what you are already doing should work fine for you.

    if error is APICallError is also working. One possibility why the if let condition fails might be due to the error being nil. Check if that is the case by using breakpoints.

    typealias APIError = (Error) -> Void
    
    //The error type used in your question
    enum APICallError: Error {
        case insufficientCredentials
        case malformedResponse
        case forbidden
    }
    
    
    //A different error type for comparison
    enum AnotherError: Error {
        case error1
        case error2
        case error3
    }
    
    let apiCallError: Error = APICallError.insufficientCredentials
    let anotherError: AnotherError  = AnotherError.error1
    
    //Closure definition
    var onError: APIError? = { inputError in
        if let apiError = inputError as? APICallError {
            print("APICallError")
        }
        if let anotherError = inputError as? AnotherError {
            print("AnotherError")
        }
    }
    
    //Above defined closure is called here below...
    onError?(apiCallError)
    onError?(anotherError)
    

    Console Output (Works as expected):

    APICallError
    AnotherError