Как предоставить локализованное описание с типом ошибки в 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, а не 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)") } }
Comments