Как предоставить локализованное описание с типом ошибки в Swift?
Я определяю пользовательский тип ошибки с синтаксисом Swift 3, и я хочу предоставить удобное описание ошибки, которая возвращается localizedDescription
свойства Error
"объект". Как я могу это сделать?
public enum MyError: Error {
case customError
var localizedDescription: String {
switch self {
case .customError:
return NSLocalizedString("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.)"
есть ли способ для localizedDescription
чтобы вернуть мое пользовательское описание ошибки ("удобное описание ошибки.")? Обратите внимание, что объект error здесь имеет тип Error
, а не MyError
. Я могу, конечно, бросить предмет в MyError
(error as? MyError)?.localizedDescription
но есть ли способ заставить его работать без литья на мои ошибки?
5 ответов
как описано в примечаниях к выпуску Xcode 8 beta 6,
Swift-определенные типы ошибок могут предоставить локализованные описания ошибок, приняв новый протокол LocalizedError.
в вашем случае:
public enum MyError: Error {
case customError
}
extension MyError: LocalizedError {
public var errorDescription: String? {
switch self {
case .customError:
return NSLocalizedString("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.
Вы могут предоставить еще больше информации, если ошибка преобразуется
к NSError
(что всегда возможно):
extension MyError : LocalizedError {
public var errorDescription: String? {
switch self {
case .customError:
return NSLocalizedString("I failed.", comment: "")
}
}
public var failureReason: String? {
switch self {
case .customError:
return NSLocalizedString("I don't know why.", comment: "")
}
}
public var recoverySuggestion: String? {
switch self {
case .customError:
return NSLocalizedString("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.")
принятие CustomNSError
протокол ошибка может обеспечить
а userInfo
словарь (а также domain
и code
). Пример:
extension MyError: CustomNSError {
public static var errorDomain: String {
return "myDomain"
}
public var errorCode: Int {
switch self {
case .customError:
return 999
}
}
public var errorUserInfo: [String : 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
Я бы также добавил, Если ваша ошибка имеет такие параметры, как это
enum NetworkError: LocalizedError {
case responseStatusError(status: Int, message: String)
}
вы можете вызвать эти параметры в локализованном описании следующим образом:
extension NetworkError {
var errorDescription: String {
switch self {
case .responseStatusError(status: let status, message: let message):
return "Error with status \(status) and message \(message) was thrown"
}
}
вы даже можете сделать это короче, как это:
extension NetworkError {
var errorDescription: String {
switch self {
case let .responseStatusError(status, message):
return "Error with status \(status) and message \(message) was thrown"
}
}
теперь есть два протокола принятия ошибок, которые ваш тип ошибки может принять, чтобы предоставить дополнительную информацию Objective-C - LocalizedError и CustomNSError. Вот пример ошибки, которая принимает оба из них:
enum MyBetterError : CustomNSError, LocalizedError {
case oops
// domain
static var errorDomain : String { return "MyDomain" }
// code
var errorCode : Int { return -666 }
// userInfo
var errorUserInfo: [String : Any] { return ["Hey":"Ho"] };
// localizedDescription
var errorDescription: String? { return "This sucks" }
// localizedFailureReason
var failureReason: String? { return "Because it sucks" }
// localizedRecoverySuggestion
var recoverySuggestion: String? { return "Give up" }
}
вот более элегантное решение:
enum ApiError: String, LocalizedError {
case invalidCredentials = "Invalid credentials"
case noConnection = "No connection"
var localizedDescription: String { return NSLocalizedString(self.rawValue, comment: "") }
}
использование структуры может быть альтернативой. Немного элегантности со статической локализацией:
import Foundation
struct MyError: LocalizedError, Equatable {
private var description: String!
init(description: String) {
self.description = description
}
var errorDescription: String? {
return description
}
public static func ==(lhs: MyError, rhs: MyError) -> Bool {
return lhs.description == rhs.description
}
}
extension MyError {
static let noConnection = MyError(description: NSLocalizedString("No internet connection",comment: ""))
static let requestFailed = MyError(description: NSLocalizedString("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)")
}
}