Lo que estoy tratando de lograr es realizar una URLSession
solicitud en swift 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 esto
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 a esta función. ¿Alguien puede decirme cómo hacer esto? ¿O no es esta la forma "rápida" de manejar estas situaciones?
ios
swift3
nsurlsession
Rikh
fuente
fuente
NSError
lugar deError
en la declaración (var errorTemp = NSError(...)
)Error
protocoloRespuestas:
Puede crear un protocolo, conforme al
LocalizedError
protocolo Swift , con estos valores:protocol OurErrorProtocol: LocalizedError { var title: String? { get } var code: Int { get } }
Esto nos permite crear errores concretos como este:
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 } }
fuente
En su caso, el error es que está intentando generar una
Error
instancia.Error
en Swift 3 es un protocolo que se puede utilizar para definir un error personalizado. Esta característica es especialmente para que las aplicaciones Swift puras se ejecuten en diferentes sistemas operativos.En el desarrollo de iOS, la
NSError
clase todavía está disponible y se ajusta alError
protocolo.Entonces, si su propósito es solo propagar este código de error, puede reemplazar fácilmente
var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
con
var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
De lo contrario, comprobar la Sandeep Bhandari 's respuesta con respecto a la forma de crear un tipo de error personalizado
fuente
Error cannot be created because it has no accessible initializers
.Error
, peroNSError
. Por supuesto, usarError
arroja un error.Puede crear enumeraciones para lidiar con 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 crea 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 Objective-C al modelo moderno orientado a protocolos usando Swift3 aquí https://learnwithmehere.blogspot.in Eche un vistazo :)
Espero eso ayude :)
fuente
Debe utilizar el objeto NSError.
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invalid access token"])
Luego lanza NSError al objeto Error
fuente
Detalles
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) }
fuente
Implementar 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 implementar 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.) "
fuente
struct StringError : LocalizedError { public let errorDescription: String? }
, y simplemente utilícelo comoStringError(errorDescription: "some message")
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error self.showLoginError(error)
crear un objeto NSError y convertirlo en Error, mostrarlo en cualquier lugar
private func showLoginError(_ error: Error?) { if let errorObj = error { UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self) } }
fuente
Sigo pensando que la respuesta de Harry es la más simple y completa, pero si necesitas algo aún más simple, usa:
struct AppError { let message: String init(message: String) { self.message = message } } extension AppError: LocalizedError { var errorDescription: String? { return message } // var failureReason: String? { get } // var recoverySuggestion: String? { get } // var helpAnchor: String? { get } }
Y utilícelo o pruébelo así:
printError(error: AppError(message: "My App Error!!!")) func print(error: Error) { print("We have an ERROR: ", error.localizedDescription) }
fuente
protocol CustomError : Error { var localizedTitle: String var localizedDescription: String } enum RequestError : Int, CustomError { 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) }
fuente
Sé que ya está satisfecho con una respuesta, pero si está interesado en conocer el enfoque correcto, 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 una respuesta y varía de 1xx a 5xx (por ejemplo, 200 OK, 408 Request timed out, 504 Gateway timeout 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 describe el objeto 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 al día" o decir 1001 para "Necesita un 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 combinan. Pero como puede ver, son completamente diferentes y muy importantes y útiles para diseñar y trabajar con software grande.
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 comprobaciones
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 :)
fuente