Создайте свой собственный код ошибки в swift 3
Я пытаюсь выполнить запрос URLSession
в swift 3. Я выполняю это действие в отдельной функции (чтобы не писать код отдельно для GET и POST) и возвращать URLSessionDataTask
и обрабатывая успех и неудачу в закрытии. Примерно так:
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!)
}
}
}
}
Я не хочу обрабатывать условие ошибки в этой функции и хочу генерировать ошибку с помощью кода ответа и возвращать эту ошибку, чтобы обрабатывать ее везде, откуда вызывается эта функция.
Может ли кто-нибудь сказать мне, как это сделать? Или это не "быстрый" способ справиться с такими ситуациями?
Ответы
Ответ 1
В вашем случае ошибка заключается в том, что вы пытаетесь создать экземпляр Error
. Error
в Swift 3 - это протокол, который может использоваться для определения пользовательской ошибки. Эта особенность особенно подходит для чистых приложений Swift для работы на разных ОС.
В iOS-разработке класс NSError
по-прежнему доступен и соответствует протоколу Error
.
Итак, если ваша цель состоит только в распространении этого кода ошибки, вы можете легко заменить
var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
с
var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
В противном случае проверьте сообщение Sandeep Bhandari о том, как создать собственный тип ошибки
Ответ 2
Вы можете создать протокол, соответствующий протоколу Swift LocalizedError
, с этими значениями:
protocol OurErrorProtocol: LocalizedError {
var title: String? { get }
var code: Int { get }
}
Это позволяет нам создавать конкретные ошибки следующим образом:
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
}
}
Ответ 3
Вы можете создавать перечисления для устранения ошибок:)
enum RikhError: Error {
case unknownError
case connectionError
case invalidCredentials
case invalidRequest
case notFound
case invalidResponse
case serverError
case serverUnavailable
case timeOut
case unsuppotedURL
}
а затем создайте метод внутри enum для получения кода ответа HTTP и верните соответствующую ошибку в ответ:)
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
}
}
Наконец, обновите свой блок отказов, чтобы принять единственный параметр типа RikhError:)
У меня есть подробное руководство по реструктуризации традиционной объектно-ориентированной сетевой модели Objective-C на современную ориентированную на протокол модель с использованием Swift3 здесь https://learnwithmehere.blogspot.in Посмотрите:)
Надеюсь, это поможет:)
Ответ 4
Вы должны использовать объект NSError.
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invalid access token"])
Затем приведите NSError к объекту Error
Ответ 5
Реализация 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
}
}
Обратите внимание, что просто реализация Error, например, как описано в одном из ответов, завершится с ошибкой (по крайней мере, в Swift 3), а вызов localizedDescription приведет к строке "Операция не может быть выполнена. (Ошибка .StringError 1.)"
Ответ 6
подробности
- Версия Xcode 10.2.1 (10E1001)
- Swift 5
Решение по организации ошибок в приложении
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
}
}
}
использование
//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)
}
Ответ 7
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error
self.showLoginError(error)
создайте объект NSError и введите его в Error, покажите его где угодно
private func showLoginError(_ error: Error?) {
if let errorObj = error {
UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self)
}
}
Ответ 8
Я знаю, что вы уже удовлетворены ответом, но если вам интересно знать правильный подход, то это может быть полезно для вас.
Я бы предпочел не смешивать код ошибки http-response с кодом ошибки в объекте ошибки (путать? Пожалуйста, продолжайте читать немного...).
Коды ответов HTTP являются стандартными кодами ошибок в отношении ответа HTTP, определяющего общие ситуации при получении ответа и варьируя от 1xx до 5xx (например, 200 OK, 408 Время ожидания запроса, 504 Тайм-аут шлюза и т.д. - http://www.restapitutorial.com/httpstatuscodes.html)
Код ошибки в объекте NSError обеспечивает очень конкретную идентификацию типа ошибки, которую объект описывает для определенного домена приложения/продукта/программного обеспечения. Например, ваше приложение может использовать 1000 для "Извините, вы не можете обновлять эту запись более одного раза в день" или сказать 1001 для "Требуется роль менеджера для доступа к этому ресурсу"..., которые относятся к вашему домену/приложению логика.
Для очень небольшого приложения иногда эти два понятия сливаются. Но они совершенно разные, как вы можете видеть, и очень важно и полезно разрабатывать и работать с большим программным обеспечением.
Таким образом, для более эффективного управления кодом могут быть два метода:
1. Обратный вызов завершения выполнит все проверки
completionHandler(data, httpResponse, responseError)
2. Ваш метод решает проблему успеха и ошибки, а затем вызывает соответствующий обратный вызов
if nil == responseError {
successCallback(data)
} else {
failureCallback(data, responseError) // failure can have data also for standard REST request/response APIs
}
Счастливое кодирование:)
Ответ 9
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)
}