Comment fournir une description localisée avec un type d’erreur dans Swift?

Je définis un type d’erreur personnalisé avec la syntaxe Swift 3 et je souhaite fournir une description conviviale de l’erreur renvoyée par la propriété localizedDescription de l’object Error . Comment puis-je le faire?

 public enum MyError: Error { case customError var localizedDescription: Ssortingng { switch self { case .customError: return NSLocalizedSsortingng("A user-friendly description of the error.", comment: "My error") } } } let error: Error = MyError.customError error.localizedDescription // "The operation couldn't be completed. (MyError error 0.)" 

Existe-t-il un moyen pour la commande localizedDescription de renvoyer ma description d’erreur personnalisée (“Une description conviviale de l’erreur”)? Notez que l’object d’erreur est de type Error et non MyError . Je peux, bien sûr, lancer l’object sur MyError

 (error as? MyError)?.localizedDescription 

mais y a-t-il un moyen de le faire fonctionner sans lancer mon type d’erreur?

Comme décrit dans les notes de version de Xcode 8 beta 6,

Les types d’erreur définis par Swift peuvent fournir des descriptions d’erreur localisées en adoptant le nouveau protocole LocalizedError.

Dans ton cas:

 public enum MyError: Error { case customError } extension MyError: LocalizedError { public var errorDescription: Ssortingng? { switch self { case .customError: return NSLocalizedSsortingng("A user-friendly description of the error.", comment: "My error") } } } let error: Error = MyError.customError print(error.localizedDescription) // A user-friendly description of the error. 

Vous pouvez fournir encore plus d’informations si l’erreur est convertie en NSError (ce qui est toujours possible):

 extension MyError : LocalizedError { public var errorDescription: Ssortingng? { switch self { case .customError: return NSLocalizedSsortingng("I failed.", comment: "") } } public var failureReason: Ssortingng? { switch self { case .customError: return NSLocalizedSsortingng("I don't know why.", comment: "") } } public var recoverySuggestion: Ssortingng? { switch self { case .customError: return NSLocalizedSsortingng("Switch it off and on again.", comment: "") } } } let error = MyError.customError as NSError print(error.localizedDescription) // I failed. print(error.localizedFailureReason) // Optional("I don\'t know why.") print(error.localizedRecoverySuggestion) // Optional("Switch it off and on again.") 

En adoptant le protocole CustomNSError , l’erreur peut fournir un dictionnaire userInfo (ainsi qu’un domain et un code ). Exemple:

 extension MyError: CustomNSError { public static var errorDomain: Ssortingng { return "myDomain" } public var errorCode: Int { switch self { case .customError: return 999 } } public var errorUserInfo: [Ssortingng : Any] { switch self { case .customError: return [ "line": 13] } } } let error = MyError.customError as NSError if let line = error.userInfo["line"] as? Int { print("Error in line", line) // Error in line 13 } print(error.code) // 999 print(error.domain) // myDomain 

Je voudrais également append, si votre erreur a des parameters comme celui-ci

 enum NetworkError: LocalizedError { case responseStatusError(status: Int, message: Ssortingng) } 

Vous pouvez appeler ces parameters dans votre description localisée comme ceci:

 extension NetworkError { var errorDescription: Ssortingng { switch self { case .responseStatusError(status: let status, message: let message): return "Error with status \(status) and message \(message) was thrown" } } 

Vous pouvez même rendre cela plus court comme ceci:

 extension NetworkError { var errorDescription: Ssortingng { switch self { case let .responseStatusError(status, message): return "Error with status \(status) and message \(message) was thrown" } } 

Il existe désormais deux protocoles d’adoption d’erreur que votre type d’erreur peut adopter pour fournir des informations supplémentaires à Objective-C-LocalizedError et CustomNSError. Voici un exemple d’erreur qui les adopte tous les deux:

 enum MyBetterError : CustomNSError, LocalizedError { case oops // domain static var errorDomain : Ssortingng { return "MyDomain" } // code var errorCode : Int { return -666 } // userInfo var errorUserInfo: [Ssortingng : Any] { return ["Hey":"Ho"] }; // localizedDescription var errorDescription: Ssortingng? { return "This sucks" } // localizedFailureReason var failureReason: Ssortingng? { return "Because it sucks" } // localizedRecoverySuggestion var recoverySuggestion: Ssortingng? { return "Give up" } } 

Voici une solution plus élégante:

  enum ApiError: Ssortingng, LocalizedError { case invalidCredentials = "Invalid credentials" case noConnection = "No connection" var localizedDescription: Ssortingng { return NSLocalizedSsortingng(self.rawValue, comment: "") } } 

Utiliser une structure peut être une alternative. Un peu d’élégance avec la localisation statique:

 import Foundation struct MyError: LocalizedError, Equatable { private var description: Ssortingng! init(description: Ssortingng) { self.description = description } var errorDescription: Ssortingng? { return description } public static func ==(lhs: MyError, rhs: MyError) -> Bool { return lhs.description == rhs.description } } extension MyError { static let noConnection = MyError(description: NSLocalizedSsortingng("No internet connection",comment: "")) static let requestFailed = MyError(description: NSLocalizedSsortingng("Request failed",comment: "")) } func throwNoConnectionError() throws { throw MyError.noConnection } do { try throwNoConnectionError() } catch let myError as MyError { switch myError { case .noConnection: print("noConnection: \(myError.localizedDescription)") case .requestFailed: print("requestFailed: \(myError.localizedDescription)") default: print("default: \(myError.localizedDescription)") } }