web-dev-qa-db-fra.com

Le moyen le plus simple de générer une erreur / une exception avec un message personnalisé dans Swift 2?

Je veux faire quelque chose dans Swift 2 que j'ai l'habitude de faire dans plusieurs autres langues: émettre une exception d'exécution avec un message personnalisé. Par exemple (en Java):

throw new RuntimeException("A custom message here")

Je comprends que je peux lancer des types d’énum conformes au protocole ErrorType, mais je ne veux pas avoir à définir d’énum pour chaque type d’erreur que je génère. Idéalement, j'aimerais pouvoir imiter l'exemple ci-dessus aussi fidèlement que possible. J'ai envisagé de créer une classe personnalisée qui implémente le protocole ErrorType, mais je ne peux même pas comprendre ce que ce protocole requiert (voir documentation ). Des idées?

119
markdb314

L’approche la plus simple consiste probablement à définir n custom enum avec un seul case auquel est associé un String:

enum MyError: ErrorType {
    case runtimeError(String)
}

Ou, à partir de Swift 4:

enum MyError: Error {
    case runtimeError(String)
}

Exemple d'utilisation serait quelque chose comme:

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

Si vous souhaitez utiliser les types Error existants, le plus général serait un NSError et vous pouvez créer une méthode fabrique pour en créer une et en envoyer une avec un message personnalisé.

171
Arkku

Le moyen le plus simple est de rendre String conforme à Error:

extension String: Error {}

Ensuite, vous pouvez simplement lancer une chaîne:

throw "Some Error"

Pour que la chaîne elle-même soit la localizedString de l'erreur, vous pouvez plutôt étendre LocalizedError:

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

La solution de @ nick-keets est très élégante, mais elle s'est effondrée dans l'objectif de test avec l'erreur de compilation suivante:

Redundant conformance of 'String' to protocol 'Error'

Voici une autre approche:

struct RuntimeError: Error {
    let message: String

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

    public var localizedDescription: String {
        return message
    }
}

Et à utiliser:

throw RuntimeError("Error message.")
17
Alexander Borisenko

Vérifiez cette version cool. L'idée est d'implémenter les protocoles String et ErrorType et d'utiliser la valeur rawValue de l'erreur.

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
}
16
Teodor Ciuraru

Swift 4:

Selon:

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

si vous ne souhaitez pas définir une exception personnalisée, vous pouvez utiliser un objet NSError standard comme suit:

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

Impressions:

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

Cela vous permet de fournir une chaîne personnalisée, un code numérique et un dictionnaire avec toutes les données supplémentaires dont vous avez besoin, quel que soit votre type.

NB: ceci a été testé sur OS = Linux (Ubuntu 16.04 LTS).

12
PJ_Finnegan

La solution la plus simple sans extensions, énumérations, classes et etc. supplémentaires:

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

Basé sur la réponse des touches @Nick, voici un exemple plus complet:

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*/
}

Publié à l'origine sur mon Swift _ blog: http://eon.codes/blog/2017/09/01/throwing-simple-errors/

4
eonist

J'aime la réponse de @ Alexander-Borisenko, mais la description localisée n'a pas été renvoyée lorsqu'elle a été interceptée comme une erreur. Il semble que vous deviez plutôt utiliser LocalizedError:

struct RuntimeError: LocalizedError
{
    let message: String

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

    public var errorDescription: String?
    {
        return message
    }
}

Voir cette réponse pour plus de détails.

3
Benjamin Smith

Il suffit d'utiliser une erreur fatalError: fatalError ("Custom message here")

1
Roney Sampaio