在 Swift 3中生成您自己的错误代码

我试图实现的是在 Swift 3中执行 URLSession请求。我将在一个单独的函数中执行这个操作(以避免为 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!)
}
}
}
}

我不希望处理这个函数中的错误条件,希望使用响应代码生成一个错误,并返回这个 Error 来处理从哪里调用这个函数。 有人能告诉我怎么做吗?或者这不是处理这种情况的“迅速”方式吗?

132432 次浏览

您可以创建枚举来处理错误:)

enum RikhError: Error {
case unknownError
case connectionError
case invalidCredentials
case invalidRequest
case notFound
case invalidResponse
case serverError
case serverUnavailable
case timeOut
case unsuppotedURL
}

and then create a method inside enum to receive the http response code and return the corresponding error in return :)

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: 的单个参数。)

I have a detailed tutorial on how to restructure traditional Objective - C based Object Oriented network model to modern Protocol Oriented model using Swift3 here https://learnwithmehere.blogspot.in Have a look :)

希望对你有所帮助:)

在您的示例中,错误在于您试图生成一个 Error实例。Swift 3中的 Error是一个可用于定义自定义错误的协议。这个特性特别适用于运行在不同操作系统上的纯 Swift 应用程序。

在 iOS 开发中,NSError类仍然可用,它符合 Error协议。

因此,如果您的目的仅仅是传播这个错误代码,那么您可以轻松地替换

var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)

var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)

否则,请检查 桑迪普 · 班达里answer,了解如何创建自定义错误类型

我知道你已经对一个答案感到满意,但是如果你有兴趣知道正确的方法,那么这可能会对你有帮助。 我不希望将 http-response 错误代码与错误对象中的错误代码混淆(混淆?请继续阅读...)。

Http 响应代码是关于 http 响应的标准错误代码,定义了接收到响应时的一般情况,从1xx 到5xx 不等(例如200 OK,408请求超时,504网关超时等等 -http://www.restapitutorial.com/httpstatuscodes.html)

The error code in a NSError object provides very specific identification to the kind of error the object describes for a particular domain of application/product/software. For example your application may use 1000 for "Sorry, You can't update this record more than once in a day" or say 1001 for "You need manager role to access this resource"... which are specific to your domain/application logic.

对于一个非常小的应用程序,有时候这两个概念会被合并。但是它们是完全不同的,正如你所看到的,它们对于大型软件的设计和工作非常重要和有帮助。

因此,有两种技术可以更好地处理代码:

1. The completion callback will perform all the checks

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
}

快乐编码:)

您可以创建一个符合 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
}
}

实现 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 将会导致字符串“ The operation could not be done。(.StringError 错误1。)”

您应该使用 NSERror 对象。

let error = NSError(domain: "", code: 401, userInfo: [ NSLocalizedDescriptionKey: "Invalid access token"])

Then cast NSError to Error object.

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)
}
 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)
}
}

细节

  • Xcode Version 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
}
}
}

Usage

//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)
}

我仍然认为哈利的答案是最简单和完整的,但如果你需要更简单的东西,那么使用:

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 }
}

像这样使用或测试:

printError(error: AppError(message: "My App Error!!!"))


func print(error: Error) {
print("We have an ERROR: ", error.localizedDescription)
}