Самый простой способ вызвать ошибку / исключение с пользовательским сообщением в Swift 2?


Я хочу сделать что-то в Swift 2, что я привык делать на нескольких других языках: бросить исключение времени выполнения с пользовательским сообщением. Например (в Java):

throw new RuntimeException("A custom message here")

Я понимаю, что я могу бросать типы перечислений, соответствующие протоколу ErrorType, но я не хочу определять перечисления для каждого типа ошибки, которую я бросаю. В идеале, я хотел бы быть в состоянии имитировать примере выше, как можно ближе. Я посмотрел на создание пользовательского класса, который реализует Протокол ErrorType, но я даже не могу понять, что этот протокол требует (см. документация). Идеи?

7 73

7 ответов:

самый простой подход, вероятно, определить один custom 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)
}

если вы хотите использовать существующий Error типы, самый общий из них будет NSError, и вы можете сделать заводской метод, чтобы создать и бросить один с пользовательским сообщением.

самый простой способ-сделать String соответствуют Error:

extension String: Error {}

тогда вы можете просто бросить строку:

throw "Some Error"

чтобы сама строка была localizedString ошибки вы можете вместо этого расширить LocalizedError:

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

проверьте эту классную версию. Идея заключается в реализации протоколов 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
}

решение@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
    }
}

и использовать:

throw RuntimeError("Error message.")

Swift 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)")
  }
}

принты:

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

Это позволяет вам предоставить пользовательскую строку, а также числовой код и словарь со всеми необходимыми дополнительными данными любого типа.

N. B.: Это было протестировано на OS=Linux (Ubuntu 16.04 LTS).

основываясь на ответе @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*/
}

Первоначально опубликовано в моем блоге swift:http://eon.коды / блог/2017/09/01/метание-простые-ошибки/

самое простое решение без дополнительных расширений, перечислений, классов и т. д.:

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