我想在Swift中做一些我习惯在其他多种语言中做的事情:用自定义消息抛出运行时异常。例如(在Java中):

throw new RuntimeException("A custom message here")

我知道我可以抛出符合ErrorType协议的枚举类型,但我不希望必须为抛出的每种类型的错误定义枚举。理想情况下,我希望能够尽可能地模拟上面的示例。我考虑创建一个实现ErrorType协议的自定义类,但我甚至不知道该协议需要什么。想法吗?


当前回答

我想对所提议的一些解决办法提出一些变通建议:

public enum MyError: Error {
    var localizedDescription: String {
        get {
            switch(self) {
                case .network(let message, let code):
                    return "\(message) (\(code))"
                case .invalidInput(message: let message):
                    return message
            }
        }
    }
    case network(message: String, code: Int)
    case invalidInput(message: String)
}

它需要更多的工作来创建,但它提供了所有世界中最好的:

它是一个枚举,所以可以在switch语句中使用。 所有错误都必须创建一个消息,即使对于相同类型的错误也可以是不同的消息(与扩展String的枚举不同) 它在localizedDescription下提供了每个开发人员都期望的消息。

其他回答

最简单的解决方案,没有额外的扩展,枚举,类等:

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

最简单的方法可能是定义一个自定义enum,只有一个case,并附加一个String:

enum MyError: ErrorType {
    case runtimeError(String)
}

或者,在Swift 4中:

enum MyError: Error {
    case runtimeError(String)
}

示例用法如下:

func someFunction() throws {
    throw MyError.runtimeError("some message")
}
do {
    try someFunction()
} catch MyError.runtimeError(let errorMessage) {
    print(errorMessage)
}

如果您希望使用现有的错误类型,最常用的错误类型是NSError,您可以创建一个工厂方法来创建并抛出一个带有自定义消息的错误类型。

我喜欢@Alexander-Borisenko的回答,但是当被捕捉为错误时,本地化的描述没有返回。看起来你需要使用LocalizedError代替:

struct RuntimeError: LocalizedError
{
    let message: String

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

    public var errorDescription: String?
    {
        return message
    }
}

更多细节请看这个答案。

抛出代码应该清楚错误消息是适合显示给最终用户还是仅用于开发人员调试。为了表明描述可以显示给用户,我使用了实现LocalizedError协议的struct DisplayableError。

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

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

投掷用途:

throw DisplayableError("Out of pixie dust.")

显示用途:

let messageToDisplay = error.localizedDescription

看看这个很酷的版本。其思想是同时实现String和ErrorType协议,并使用错误的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."
}

用法:

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
}