신속한 3에서 자신의 오류 코드 생성


88

내가 달성하려는 URLSession것은 신속한 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!)
               }
          }
     }
}

이 함수에서 오류 조건을 처리하고 싶지 않고 응답 코드를 사용하여 오류를 생성하고이 함수가 호출 될 때마다 처리하기 위해이 오류를 반환하고 싶습니다. 아무도 이것에 대해 어떻게 나에게 말할 수 있습니까? 아니면 이러한 상황을 처리하는 "신속한"방법이 아닙니까?


NSError대신 Error선언 ( var errorTemp = NSError(...))을 사용해보십시오
Luca D' Alberti

그것은 문제를 해결하지만 swift 3은 NS를 계속 사용하고 싶지 않다고 생각했습니다.
Rikh 2011

iOS 개발에서 이루어집니다. 순수한 Swift 개발의 경우 Error프로토콜 을 준수하여 고유 한 오류 인스턴스를 만들어야합니다.
Luca D' Alberti

@ LucaD'Alberti 글쎄요, 당신의 솔루션이 문제를 해결 했으니, 제가 그것을 받아 들일 수 있도록 대답으로 자유롭게 추가하세요!
Rikh 2011

답변:


72

LocalizedError다음 값 을 사용하여 Swift 프로토콜을 준수하는 프로토콜을 만들 수 있습니다 .

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
a) OurErrorProtocol을 생성 할 필요는 없으며 CustomError가 직접 오류를 구현하도록합니다. b) 작동하지 않습니다 (적어도 Swift 3에서는 localizedDescription이 호출되지 않고 "작업을 완료 할 수 없습니다."라는 메시지가 표시됨). 대신 LocalizedError를 구현해야합니다. 내 대답을 참조하십시오.
prewett

@prewett 방금 알아 차 렸지만 당신이 옳습니다! 실제로 LocalizedError에서 errorDescription 필드를 구현하면 위에서 설명한대로 내 메서드를 사용하는 대신 메시지가 설정됩니다. localizedTitle 필드도 필요하므로 "OurErrorProtocol"래퍼를 계속 유지하고 있습니다. 지적 해 주셔서 감사합니다!
Harry Bloom

106

귀하의 경우 오류는 Error인스턴스 생성을 시도하고 있다는 것 입니다. ErrorSwift 3에서 사용자 지정 오류를 정의하는 데 사용할 수있는 프로토콜입니다. 이 기능은 특히 순수한 Swift 애플리케이션이 다른 OS에서 실행되는 데 적합합니다.

iOS 개발에서 NSError클래스는 계속 사용할 수 있으며 Error프로토콜을 준수 합니다.

따라서이 오류 코드를 전파하는 것이 목적이라면

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

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

그렇지 않으면 사용자 지정 오류 유형을 만드는 방법에 대한 Sandeep Bhandari답변을 확인하십시오.


15
오류가 발생 Error cannot be created because it has no accessible initializers합니다..
Supertecnoboff

@AbhishekThapliyal 귀하의 의견을 좀 더 자세히 설명해 주시겠습니까? 무슨 말인지 이해할 수 없습니다.
Luca D' Alberti

2
@ LucaD'Alberti는 Swift 4에서와 같이 Error Object를 생성하는 동안 액세스 가능한 이니셜 라이저가 없기 때문에 Error를 생성 할 수 없습니다.
Maheep

1
@Maheep 내가 내 대답에서 제안하는 것은 사용하지 않는 Error것이지만 NSError. 물론 사용 Error하면 오류가 발생합니다.
Luca D' Alberti

오류는 프로토콜입니다. 직접 인스턴스화 할 수 없습니다.
slobodans

52

오류를 처리하기 위해 열거 형을 만들 수 있습니다. :)

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 기반 Object Oriented 네트워크 모델을 Swift3를 사용하여 현대적인 Protocol Oriented 모델로 재구성하는 방법에 대한 자세한 자습서가 있습니다 https://learnwithmehere.blogspot.in 살펴보세요 :)

도움이되기를 바랍니다 :)


아,하지만 모든 사건을 수동으로 처리 할 필요는 없나요? 그것이 오류 코드 유형입니까?
Rikh

Yup 당신은해야합니다 : D 그러나 동시에 당신은 각 오류 상태에 특정한 다양한 조치를 취할 수 있습니다 :) 이제 당신이 그것을하고 싶지 않다면 당신은 사례 400 ... 404를 사용할 수 있습니다. {...} 다만 일반적인 경우를 :) 처리
하기 Sandeep 반 다리

아 예! 감사합니다
Rikh

여러 http 코드가 동일한 경우를 가리킬 필요가 없다고 가정하면 enum RikhError : Int, Error {case invalidRequest = 400} 그런 다음 생성 할 수 있어야합니다. RikhError (rawValue : httpCode)
Brian F Leighty

48

NSError 객체를 사용해야합니다.

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

그런 다음 NSError를 Error 객체로 캐스팅합니다.


27

세부

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

16

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 completed. (. StringError error 1)"라는 문자열이 생성됩니다. "


mmsg = msg
Brett

1
아, 맞아. 나는 "msg"를 "description"으로 변경했는데, 이것은 내 원본보다 조금 더 명확하기를 바란다.
prewett

4
당신은 그에게 줄일 수 있습니다 struct StringError : LocalizedError { public let errorDescription: String? }, 그것은 간단하게 사용StringError(errorDescription: "some message")
공원.

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

4

나는 여전히 Harry의 대답이 가장 간단하고 완성되었다고 생각하지만 더 간단한 것이 필요하면 다음을 사용하십시오.

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

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

1

이미 답변에 만족하신 것을 알고 있지만 올바른 접근 방식을 알고 싶다면이 방법이 도움이 될 수 있습니다. http- 응답 오류 코드와 오류 개체의 오류 코드를 혼합하지 않는 것이 좋습니다 (혼란 스럽습니까? 계속해서 조금 읽으십시오 ...).

http 응답 코드는 응답이 수신 될 때 일반적인 상황을 정의하는 http 응답에 대한 표준 오류 코드이며 1xx에서 5xx까지 다양합니다 (예 : 200 OK, 408 Request timed, 504 Gateway timeout 등-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
}

해피 코딩 :)


그래서 기본적으로 서버에서 반환 된 특정 오류 코드의 경우 표시 할 특정 문자열이있는 경우 "data"매개 변수를 전달하는 것입니다. (죄송합니다.
가끔
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.