Codakuma
iOS apps and more

Making your own errors in Swift

31 Dec 2020

Swift’s Error protocol is commonly used across Apple’s APIs to represent failure states.

Typically, it’s used like this:

HKHealthStore().disableAllBackgroundDelivery { (success, errorOrNil) in
  if let error = errorOrNil {
    print(error.localizedDescription)
  }
}

Example of an Error that can be returned from a HealthKit method.

Recently I wanted to create my own instance of Error, like this:

func doSomethingAsync(onComplete: @escaping (Bool, Error?) -> Void) {
  let result = SomeClass.methodThatMightCauseError()
  if result {
      onComplete(true, nil)
  } else {
      onComplete(false, Error("Failed to do the thing"))
  }
}

Because Error is a protocol, it cannot be constructed directly and the above code won’t work. To fix it, we need to make a simple struct that implements the protocol, like this:

struct AppError {
  let message: String

  init(_ message: String) {
    self.message = message
  }
}

extension AppError: LocalizedError {
  var errorDescription: String? { return message }
}

Now, the code from earlier can be changed to make an instance of AppError:

onComplete(false, AppError("Failed to do the thing"))

Credit to Reimond Hill on StackOverflow for pointing me in the right direction here.

And that’s it. This is pretty much the simplest implementation of Error you could make. It’ll work fine for trivial uses, but you may wish to implement more of the procotol for more robust error handling, for example be adding recovery suggestions, help anchors and error codes. Those are out of scope for this post, but Apple’s own documentation is a good place to go from if you’d like to learn more.