ios - library - Genere su propio código de error en Swift 3
swift libraries (9)
Lo que estoy tratando de lograr es realizar una solicitud
URLSession
en
URLSession
3. Estoy realizando esta acción en una función separada (para no escribir el código por separado para GET y POST) y devolviendo
URLSessionDataTask
y manejando el éxito y el fracaso en los cierres .
Algo así como
let task = URLSession.shared.dataTask(with: request) { (data, uRLResponse, responseError) in
DispatchQueue.main.async {
var httpResponse = uRLResponse as! HTTPURLResponse
if responseError != nil && httpResponse.statusCode == 200{
successHandler(data!)
}else{
if(responseError == nil){
//Trying to achieve something like below 2 lines
//Following line throws an error soo its not possible
//var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
//failureHandler(errorTemp)
}else{
failureHandler(responseError!)
}
}
}
}
No deseo manejar la condición de error en esta función y deseo generar un error usando el código de respuesta y devolver este error para manejarlo desde donde se llame esta función. ¿Alguien puede decirme cómo hacer esto? ¿O no es esta la forma "rápida" de manejar tales situaciones?
Detalles
- Xcode versión 10.2.1 (10E1001)
- Swift 5
Solución de errores de organización en una aplicación.
import Foundation
enum AppError {
case network(type: Enums.NetworkError)
case file(type: Enums.FileError)
case custom(errorDescription: String?)
class Enums { }
}
extension AppError: LocalizedError {
var errorDescription: String? {
switch self {
case .network(let type): return type.localizedDescription
case .file(let type): return type.localizedDescription
case .custom(let errorDescription): return errorDescription
}
}
}
// MARK: - Network Errors
extension AppError.Enums {
enum NetworkError {
case parsing
case notFound
case custom(errorCode: Int?, errorDescription: String?)
}
}
extension AppError.Enums.NetworkError: LocalizedError {
var errorDescription: String? {
switch self {
case .parsing: return "Parsing error"
case .notFound: return "URL Not Found"
case .custom(_, let errorDescription): return errorDescription
}
}
var errorCode: Int? {
switch self {
case .parsing: return nil
case .notFound: return 404
case .custom(let errorCode, _): return errorCode
}
}
}
// MARK: - FIle Errors
extension AppError.Enums {
enum FileError {
case read(path: String)
case write(path: String, value: Any)
case custom(errorDescription: String?)
}
}
extension AppError.Enums.FileError: LocalizedError {
var errorDescription: String? {
switch self {
case .read(let path): return "Could not read file from /"/(path)/""
case .write(let path, let value): return "Could not write value /"/(value)/" file from /"/(path)/""
case .custom(let errorDescription): return errorDescription
}
}
}
Uso
//let err: Error = NSError(domain:"", code: 401, userInfo: [NSLocalizedDescriptionKey: "Invaild UserName or Password"])
let err: Error = AppError.network(type: .custom(errorCode: 400, errorDescription: "Bad request"))
switch err {
case is AppError:
switch err as! AppError {
case .network(let type): print("Network ERROR: code /(type.errorCode), description: /(type.localizedDescription)")
case .file(let type):
switch type {
case .read: print("FILE Reading ERROR")
case .write: print("FILE Writing ERROR")
case .custom: print("FILE ERROR")
}
case .custom: print("Custom ERROR")
}
default: print(err)
}
Debe usar el objeto NSError.
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invalid access token"])
Luego envíe el objeto NSError to Error
En su caso, el error es que está intentando generar una instancia de
Error
.
Error
en Swift 3 es un protocolo que puede usarse para definir un error personalizado.
Esta característica es especialmente para aplicaciones Swift puras que se ejecutan en diferentes sistemas operativos.
En el desarrollo de iOS, la clase
NSError
todavía está disponible y se ajusta al protocolo de
Error
.
Entonces, si su propósito es solo propagar este código de error, puede reemplazarlo fácilmente
var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
con
var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
De lo contrario, verifique la answer Sandeep Bhandari sobre cómo crear un tipo de error personalizado
Implemente LocalizedError:
struct StringError : LocalizedError
{
var errorDescription: String? { return mMsg }
var failureReason: String? { return mMsg }
var recoverySuggestion: String? { return "" }
var helpAnchor: String? { return "" }
private var mMsg : String
init(_ description: String)
{
mMsg = description
}
}
Tenga en cuenta que simplemente implementando Error, por ejemplo, como se describe en una de las respuestas, fallará (al menos en Swift 3), y llamar a localizedDescription dará como resultado la cadena "La operación no se pudo completar. (.StringError error 1.) "
Puede crear enumeraciones para tratar los errores :)
enum RikhError: Error {
case unknownError
case connectionError
case invalidCredentials
case invalidRequest
case notFound
case invalidResponse
case serverError
case serverUnavailable
case timeOut
case unsuppotedURL
}
y luego cree un método dentro de enum para recibir el código de respuesta http y devolver el error correspondiente a cambio :)
static func checkErrorCode(_ errorCode: Int) -> RikhError {
switch errorCode {
case 400:
return .invalidRequest
case 401:
return .invalidCredentials
case 404:
return .notFound
//bla bla bla
default:
return .unknownError
}
}
Finalmente actualice su bloque de falla para aceptar un solo parámetro de tipo RikhError :)
Tengo un tutorial detallado sobre cómo reestructurar el modelo de red tradicional orientado a objetos basado en C a un modelo moderno orientado a protocolos usando Swift3 aquí https://learnwithmehere.blogspot.in Eche un vistazo :)
Espero eso ayude :)
Puede crear un protocolo, conforme al protocolo Swift
LocalizedError
, con estos valores:
protocol OurErrorProtocol: LocalizedError {
var title: String? { get }
var code: Int { get }
}
Esto nos permite crear errores concretos de la siguiente manera:
struct CustomError: OurErrorProtocol {
var title: String?
var code: Int
var errorDescription: String? { return _description }
var failureReason: String? { return _description }
private var _description: String
init(title: String?, description: String, code: Int) {
self.title = title ?? "Error"
self._description = description
self.code = code
}
}
Sé que ya está satisfecho con una respuesta, pero si está interesado en conocer el enfoque correcto, entonces esto podría ser útil para usted. Preferiría no mezclar el código de error de respuesta http con el código de error en el objeto de error (¿confundido? Continúe leyendo un poco ...).
Los códigos de respuesta http son códigos de error estándar sobre una respuesta http que define situaciones genéricas cuando se recibe la respuesta y varía de 1xx a 5xx (por ejemplo, 200 OK, 408 Tiempo de solicitud agotado, 504 Tiempo de espera de puerta de enlace, etc.) - http://www.restapitutorial.com/httpstatuscodes.html )
El código de error en un objeto NSError proporciona una identificación muy específica del tipo de error que el objeto describe para un dominio particular de aplicación / producto / software. Por ejemplo, su aplicación puede usar 1000 para "Lo sentimos, no puede actualizar este registro más de una vez en un día" o decir 1001 para "Necesita el rol de administrador para acceder a este recurso" ... que son específicos de su dominio / aplicación lógica.
Para una aplicación muy pequeña, a veces estos dos conceptos se fusionan. Pero, como puede ver, son completamente diferentes y muy importantes y útiles para diseñar y trabajar con software de gran tamaño.
Entonces, puede haber dos técnicas para manejar el código de una mejor manera:
1. La devolución de llamada de finalización realizará todas las verificaciones
completionHandler(data, httpResponse, responseError)
2. Su método decide la situación de éxito y error y luego invoca la devolución de llamada correspondiente
if nil == responseError {
successCallback(data)
} else {
failureCallback(data, responseError) // failure can have data also for standard REST request/response APIs
}
Feliz codificación :)
protocol CustomError : Error {
var localizedTitle: String
var localizedDescription: String
}
enum RequestError : Int, Error {
case badRequest = 400
case loginFailed = 401
case userDisabled = 403
case notFound = 404
case methodNotAllowed = 405
case serverError = 500
case noConnection = -1009
case timeOutError = -1001
}
func anything(errorCode: Int) -> CustomError? {
return RequestError(rawValue: errorCode)
}
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error
self.showLoginError(error)
cree un objeto NSError y escríbalo en Error, muéstrelo en cualquier lugar
private func showLoginError(_ error: Error?) {
if let errorObj = error {
UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self)
}
}