Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way to compare errors in Swift?

Tags:

I have this error:

public enum AuthenticationError: Error {     case unknownError     case canceledByUser     case userOrPasswordMismatch     case unableToExtractOneTimeCode     case unableToExchangeOneTimeCodeForToken     case credentialsUnavailable     case expired     case webRequestFailed(error: Error) } 

I'd like to overload == to compare it but I find I need to repeat the code three ways:

public func == (lhs: Error, rhs: AuthenticationError) -> Bool {    return lhs._code == rhs._code && lhs._domain == rhs._domain }  public func == (lhs: AuthenticationError, rhs: Error) -> Bool public func == (lhs: AuthenticationError, rhs: AuthenticationError) -> Bool 

An usage example is:

if let error = error, error == AuthenticationError.expired {    // do something } 

Is there a better way to do this (with generics) so I don't need to repeat similar code?

like image 671
Jason Leach Avatar asked Apr 04 '18 19:04

Jason Leach


People also ask

How do I compare references in Swift?

This is by using the === operator. The === operator checks if two reference type variables point to the same object in memory. Now you understand how the === operator works in Swift classes and why it is important.

Do catch vs try catch Swift?

do – This keyword starts the block of code that contains the method that can potentially throw an error. try – You must use this keyword in front of the method that throws. Think of it like this: “You're trying to execute the method.

What is the difference between try and try in Swift?

Similar to try? , try! doesn't need to be put inside do/catch block as well. The difference is that when an error is thrown, your app will crash instead of returning nil. This is similar to unwrapping a nil value in optionals.


1 Answers

This suffices for your .expired check, without needing to define ==:

let error: Error = ... if case AuthenticationError.expired = error {     print("it's expired") } 

If you want to extract associated data (as in the .webRequestFailed case), you can do this:

if case AuthenticationError.webRequestFailed(error: let innerError) = error {     print("web request failed due to \(innerError.localizedDescription)") } 

Here's my macOS playground, created in Xcode 9.2:

import Foundation  public enum AuthenticationError: Error {     case unknownError     case canceledByUser     case userOrPasswordMismatch     case unableToExtractOneTimeCode     case unableToExchangeOneTimeCodeForToken     case credentialsUnavailable     case expired     case webRequestFailed(error: Error) }  func test(_ error: Error) {     if case AuthenticationError.expired = error {         print("it's expired; error = \(error)")     } else if case AuthenticationError.webRequestFailed(error: let innerError) = error {         print("web request failed due to \(innerError.localizedDescription); error = \(error)")     } else {         print("no match; error = \(error)")     } }  test(AuthenticationError.expired) test(AuthenticationError.webRequestFailed(error: AuthenticationError.credentialsUnavailable)) test(NSError(domain: NSPOSIXErrorDomain, code: Int(ENOENT), userInfo: [:])) 
like image 52
rob mayoff Avatar answered Oct 01 '22 00:10

rob mayoff