[ios] Simplest way to throw an error/exception with a custom message in Swift 2?

I want to do something in Swift 2 that I'm used to doing in multiple other languages: throw a runtime exception with a custom message. For example (in Java):

throw new RuntimeException("A custom message here")

I understand that I can throw enum types that conform to the ErrorType protocol, but I don't want to have to define enums for every type of error I throw. Ideally, I'd like to be able mimic the example above as closely as possible. I looked into creating a custom class that implements the ErrorType protocol, but I can't even figure out that what that protocol requires (see documentation). Ideas?

This question is related to ios swift swift2

The answer is


Swift 4:

As per:

https://developer.apple.com/documentation/foundation/nserror

if you don't want to define a custom exception, you could use a standard NSError object as follows:

import Foundation

do {
  throw NSError(domain: "my error domain", code: 42, userInfo: ["ui1":12, "ui2":"val2"] ) 
}
catch let error as NSError {
  print("Caught NSError: \(error.localizedDescription), \(error.domain), \(error.code)")
  let uis = error.userInfo 
  print("\tUser info:")
  for (key,value) in uis {
    print("\t\tkey=\(key), value=\(value)")
  }
}

Prints:

Caught NSError: The operation could not be completed, my error domain, 42
    User info:
        key=ui1, value=12
        key=ui2, value=val2

This allows you to provide a custom string (the error domain), plus a numeric code and a dictionary with all the additional data you need, of any type.

N.B.: this was tested on OS=Linux (Ubuntu 16.04 LTS).


Check this cool version out. The idea is to implement both String and ErrorType protocols and use the error's rawValue.

enum UserValidationError: String, Error {
  case noFirstNameProvided = "Please insert your first name."
  case noLastNameProvided = "Please insert your last name."
  case noAgeProvided = "Please insert your age."
  case noEmailProvided = "Please insert your email."
}

Usage:

do {
  try User.define(firstName,
                  lastName: lastName,
                  age: age,
                  email: email,
                  gender: gender,
                  location: location,
                  phone: phone)
}
catch let error as User.UserValidationError {
  print(error.rawValue)
  return
}

Throwing code should make clear whether the error message is appropriate for display to end users or is only intended for developer debugging. To indicate a description is displayable to the user, I use a struct DisplayableError that implements the LocalizedError protocol.

struct DisplayableError: Error, LocalizedError {
    let errorDescription: String?

    init(_ description: String) {
        errorDescription = description
    }
}

Usage for throwing:

throw DisplayableError("Out of pixie dust.")

Usage for display:

let messageToDisplay = error.localizedDescription

The simplest way is to make String conform to Error:

extension String: Error {}

Then you can just throw a string:

throw "Some Error"

To make the string itself be the localizedString of the error you can instead extend LocalizedError:

extension String: LocalizedError {
    public var errorDescription: String? { return self }
}

In case you don't need to catch the error and you want to immediately stop the application you can use a fatalError: fatalError ("Custom message here")


Based on @Nick keets answer, here is a more complete example:

extension String: Error {} // Enables you to throw a string

extension String: LocalizedError { // Adds error.localizedDescription to Error instances
    public var errorDescription: String? { return self }
}

func test(color: NSColor) throws{
    if color == .red {
        throw "I don't like red"
    }else if color == .green {
        throw "I'm not into green"
    }else {
        throw "I like all other colors"
    }
}

do {
    try test(color: .green)
} catch let error where error.localizedDescription == "I don't like red"{
    Swift.print ("Error: \(error)") // "I don't like red"
}catch let error {
    Swift.print ("Other cases: Error: \(error.localizedDescription)") // I like all other colors
}

Originally published on my swift blog: http://eon.codes/blog/2017/09/01/throwing-simple-errors/


I like @Alexander-Borisenko's answer, but the localized description was not returned when caught as an Error. It seems that you need to use LocalizedError instead:

struct RuntimeError: LocalizedError
{
    let message: String

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

    public var errorDescription: String?
    {
        return message
    }
}

See this answer for more details.


Simplest solution without extra extensions, enums, classes and etc.:

NSException(name:NSExceptionName(rawValue: "name"), reason:"reason", userInfo:nil).raise()

@nick-keets's solution is most elegant, but it did break down for me in test target with the following compile time error:

Redundant conformance of 'String' to protocol 'Error'

Here's another approach:

struct RuntimeError: Error {
    let message: String

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

    public var localizedDescription: String {
        return message
    }
}

And to use:

throw RuntimeError("Error message.")

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to swift

Make a VStack fill the width of the screen in SwiftUI Xcode 10.2.1 Command PhaseScriptExecution failed with a nonzero exit code Command CompileSwift failed with a nonzero exit code in Xcode 10 Convert Json string to Json object in Swift 4 iOS Swift - Get the Current Local Time and Date Timestamp Xcode 9 Swift Language Version (SWIFT_VERSION) How do I use Safe Area Layout programmatically? How can I use String substring in Swift 4? 'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator Safe Area of Xcode 9 The use of Swift 3 @objc inference in Swift 4 mode is deprecated?

Examples related to swift2

Swift Modal View Controller with transparent background Simplest way to throw an error/exception with a custom message in Swift 2? Swift's guard keyword Swift do-try-catch syntax Get integer value from string in swift