在Swift 2中使用自定义消息抛出错误/异常的最简单方法?

mar*_*314 125 ios swift swift2

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

throw new RuntimeException("A custom message here")
Run Code Online (Sandbox Code Playgroud)

我知道我可以抛出符合ErrorType协议的枚举类型,但我不想为我抛出的每种类型的错误定义枚举.理想情况下,我希望能够尽可能地模仿上面的例子.我研究了创建一个实现ErrorType协议的自定义类,但我甚至无法弄清楚该协议需要什么(参见文档).想法?

Ark*_*kku 174

最简单的方法可能是定义一个定制的enum只有一个case是有一个String连接到它:

enum MyError: ErrorType {
    case runtimeError(String)
}
Run Code Online (Sandbox Code Playgroud)

或者,从Swift 4开始:

enum MyError: Error {
    case runtimeError(String)
}
Run Code Online (Sandbox Code Playgroud)

示例用法如下:

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

如果您希望使用现有Error类型,那么最常用的类型就是a NSError,您可以创建一个工厂方法来创建一个带有自定义消息的方法.

  • @RenanCamaforte 抱歉,我不明白这个问题?这里的“String”与“MyError.RuntimeError”相关联(在“throw”时设置),并且您可以在“catch”处访问它(使用“let errorMessage”)。 (2认同)
  • 您被要求提供最简单的解决方案。创建自定义枚举、函数等时的解决方案并不简单。我至少知道一种方法,但我不会在那里发布,因为它是针对 Objective-C 的 (2认同)
  • @VyachaslavGerchicov如果您不知道在问题中也指定了Swift的更简单方法,那么这将是_simplest_方式,即使您在包括Objective-C在内的更一般的上下文中也不认为这是简单的方法。(此外,此答案基本上是一个枚举的单行一次性定义,该函数及其调用是用法的一个示例,而不是解决方案的一部分。) (2认同)
  • @Otar 是的,但是……您说的是 `try!`,此处未使用。如果没有某种“try”,您确实甚至无法进行潜在的抛出调用。(还有那部分代码是示例用法,而不是实际解决方案。) (2认同)

Nic*_*ets 123

最简单的方法是String遵守Error:

extension String: Error {}
Run Code Online (Sandbox Code Playgroud)

然后你可以抛出一个字符串:

throw "Some Error"
Run Code Online (Sandbox Code Playgroud)

要使字符串本身成为localizedString错误,您可以改为LocalizedError:

extension String: LocalizedError {
    public var errorDescription: String? { return self }
}
Run Code Online (Sandbox Code Playgroud)

  • 这肯定会在抛出错误的位置提供最佳的简单语法,并且在这种意义上确实优于我(当前接受的)答案.但是,我个人觉得将`String`这样的基本类型扩展为`Error`有点令人反感.再说一次,我也没有在实际代码中使用我自己的解决方案,(我宁愿为每个错误定义一个单独的枚举案例),所以我不确定该参数是否与寻求者有关在throw-site定义错误消息.=) (3认同)
  • 协议应该声明类型“是什么”,而不是它“可能是什么”。字符串并不总是错误,这个扩展很容易让人意外地认为它是错误,从而破坏了类型安全。 (3认同)
  • 确实优雅!但它在测试目标中对我来说崩溃了,并显示以下消息“‘字符串’与协议‘错误’的冗余一致性’:( (2认同)
  • 由于某种原因,这对我不起作用。说抛出字符串后解析`error.localizedDescription`时无法完成操作。 (2认同)
  • 警告:此扩展给我带来了外部库的问题。[这是我的例子](https://github.com/google/promises/issues/88#issuecomment-572838985)。这对于任何管理错误的第三方库都是可能的;我会避免使 String 符合 Error 的扩展。 (2认同)

Ale*_*nko 19

@ nick-keets的解决方案是最优雅的,但它在测试目标中为我打破了以下编译时错误:

Redundant conformance of 'String' to protocol 'Error'

这是另一种方法:

struct RuntimeError: Error {
    let message: String

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

    public var localizedDescription: String {
        return message
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用:

throw RuntimeError("Error message.")
Run Code Online (Sandbox Code Playgroud)


Teo*_*aru 18

检查这个很酷的版本.我们的想法是实现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."
}
Run Code Online (Sandbox Code Playgroud)

用法:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 更好地实现 localizedDescription 方法以返回 .rawValue (2认同)

PJ_*_*gan 14

斯威夫特4:

按照:

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

如果您不想定义自定义异常,可以使用标准NSError对象,如下所示:

import Foundation

do {
  throw NSError(domain: "my error description", 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)")
  }
}
Run Code Online (Sandbox Code Playgroud)

打印:

Caught NSError: The operation could not be completed, my error description, 42
    User info:
        key=ui1, value=12
        key=ui2, value=val2
Run Code Online (Sandbox Code Playgroud)

这允许您提供自定义字符串,以及包含任何类型所需的所有其他数据的数字代码和字典.

注意:这是在OS = Linux(Ubuntu 16.04 LTS)上测试的.

  • 将“我的错误描述”传递给名为“domain”的参数似乎超出了 API 的意图。 (3认同)
  • 该修复突出了第二个问题:catch 块具有“error.localizedDescription”,但该描述未设置为 throw 语句中的任何内容。因此,您最终只会得到一个通用的“操作无法完成”错误。 (2认同)

Ron*_*aio 9

如果您不需要捕获错误并且想立即停止应用程序,您可以使用致命错误: fatalError ("Custom message here")

  • 请注意,这不会引发可捕获的错误。这将使应用程序崩溃。 (3认同)

Vya*_*cov 7

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

NSException(name:NSExceptionName(rawValue: "name"), reason:"reason", userInfo:nil).raise()
Run Code Online (Sandbox Code Playgroud)

  • 关于。你对我的回答的评论,这只是因为你有点武断地决定定义和枚举或扩展 _once_ 是复杂的。所以,是的,你的答案有零行“设置”,但代价是让 _every_ 抛出异常成为一个复杂且非 Swift 的(`raise()` 而不是 `throw`)咒语,很难记住。将您的解决方案与 `throw Foo.Bar("baz")` 或 `throw "foo"` 乘以抛出异常的地方的数量相比较——IMO 单行扩展或枚举的一次性费用更可取到诸如“NSExceptionName”之类的东西。 (2认同)
  • 不,我什至不会在自己的答案中使用该解决方案;我发布它只是为了回答这个问题,而不是因为这是我自己会做的事情。无论如何,这不是重点:我坚持认为您的答案_使用__比我的或尼克基茨的答案复杂得多。当然还有其他有效的点需要考虑,例如扩展 `String` 以符合 `Error` 是否太令人惊讶,或者 `MyError` 枚举是否太模糊(我个人都会对两者都回答是,而是做一个每个错误的单独枚举案例,即`throw ThisTypeOfError.thisParticularCase`)。 (2认同)

eon*_*ist 5

基于@Nick keets的答案,这是一个更完整的示例:

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
}
Run Code Online (Sandbox Code Playgroud)

最初发布在我的快速博客上:http : //eon.codes/blog/2017/09/01/throwing-simple-errors/

  • TBH:我现在只是做“抛出 NSError(message: "err", code: 0)` (2认同)