【问题标题】:Generate your own Error code in swift 3在 swift 3 中生成您自己的错误代码
【发布时间】:2017-04-02 00:06:02
【问题描述】:

我想要实现的是在 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!)
               }
          }
     }
}

我不希望处理此函数中的错误情况,并希望使用响应代码生成错误并返回此错误以在调用此函数的任何位置进行处理。 谁能告诉我该怎么做?或者这不是处理这种情况的“Swift”方式吗?

【问题讨论】:

  • 尝试在声明中使用NSError 而不是Error (var errorTemp = NSError(...))
  • 这解决了问题,但我认为 swift 3 不想继续使用 NS?
  • 在 iOS 开发中确实如此。对于纯 Swift 开发,您应该通过遵循 Error 协议来创建自己的错误实例
  • @LucaD'Alberti 好吧,您的解决方案确实解决了问题,请随时将其添加为答案,以便我接受!

标签: ios swift3 nsurlsession


【解决方案1】:

你应该使用 NSError 对象。

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

然后将 NSError 转换为 Error 对象。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:
      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)
      }
      

      【讨论】:

        【解决方案4】:

        详情

        • Xcode 版本 10.2.1 (10E1001)
        • 斯威夫特 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)
        }
        

        【讨论】:

          【解决方案5】:
           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)
              }
          }
          

          【讨论】:

            【解决方案6】:

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

            请注意,例如,如其中一个答案中所述,简单地实现错误将失败(至少在 Swift 3 中),并且调用本地化描述将导致字符串“操作无法完成。(.StringError 错误1.)"

            【讨论】:

            • 应该是mMsg = msg
            • 糟糕,对。我将“msg”更改为“description”,希望比我原来的更清晰。
            • 您可以将其缩减为struct StringError : LocalizedError { public let errorDescription: String? },然后简单地用作StringError(errorDescription: "some message")
            【解决方案7】:

            您可以使用以下值创建符合 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
                }
            }
            

            【讨论】:

            • a) 不需要创建OurErrorProtocol,直接让CustomError 实现Error即可。 b)这不起作用(至少在 Swift 3 中:从不调用本地化描述,并且您得到“无法完成操作。”)。您需要改为实现 LocalizedError ;看我的回答。
            • @prewett 我刚刚注意到,但你是对的!在 LocalizedError 中实现 errorDescription 字段实际上设置了消息,而不是如上所述使用我的方法。不过,我仍然保留“OurErrorProtocol”包装器,因为我还需要localizedTitle 字段。感谢您指出这一点!
            【解决方案8】:

            在您的情况下,错误是您正在尝试生成 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)
            

            否则,请查看 Sandeep Bhandarianswer,了解如何创建自定义错误类型

            【讨论】:

            • 我刚刚收到错误消息:Error cannot be created because it has no accessible initializers
            • @AbhishekThapliyal 您能否详细说明您的评论?我不明白你的意思。
            • @LucaD'Alberti 与 Swift 4 一样,它显示的错误无法创建,因为它在创建错误对象时没有可访问的初始化程序。
            • @Maheep 我在回答中的建议不是使用Error,而是使用NSError。当然使用Error 会引发错误。
            • 错误是协议。不能直接实例化。
            【解决方案9】:

            我知道您已经对答案感到满意,但如果您有兴趣了解正确的方法,那么这可能对您有所帮助。 我不希望将 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
            }
            

            编码愉快:)

            【讨论】:

            • 所以基本上你想说的是传递“数据”参数,以防在服务器返回特定错误代码的情况下显示一些特定的字符串? (对不起,我有时会有点慢!)
            【解决方案10】:

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

            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 响应码并在 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 类型的单个参数:)

            我有一个详细的教程,关于如何使用 Swift3 将传统的基于 Objective-C 的面向对象的网络模型重构为现代的面向协议的模型https://learnwithmehere.blogspot.in 看看 :)

            希望对你有帮助:)

            【讨论】:

            • 啊,但这不会让我手动处理所有情况吗?那就是输入错误码?
            • 是的,你必须:D 但同时你可以针对每个错误状态采取各种行动可以用 case 400 ... 404 {... } 处理一般情况:)
            • 啊是的!谢谢
            • 假设多个http代码不需要指向同一个案例,你应该能够做 enum RikhError: Int, Error { case invalidRequest = 400 } 然后创建它 RikhError(rawValue: http代码)
            猜你喜欢
            • 2014-08-17
            • 2010-09-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-01-09
            • 2017-03-14
            • 1970-01-01
            相关资源
            最近更新 更多