Swift 3'te kendi Hata kodunuzu oluşturun


91

Başarmaya çalıştığım şey URLSession, hızlı bir şekilde bir istek yapmak URLSessionDataTask. Bunun gibi ...

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

Bu işlevdeki hata durumunu ele almak istemiyorum ve yanıt kodunu kullanarak bir hata oluşturmak ve bu işlevin çağrıldığı her yerde bu Hatayı işlemek için bu Hatayı döndürmek istiyorum. Biri bana bunun nasıl yapılacağını söyleyebilir mi? Yoksa bu tür durumlarla başa çıkmanın "Hızlı" yolu bu değil mi?


Bildirim NSErroryerine kullanmayı deneyin Error( var errorTemp = NSError(...))
Luca D'Alberti

Bu sorunu çözdü, ancak Swift 3'ün NS'yi kullanmaya devam etmek istemediğini düşündüm.
Rikh

İOS geliştirmede işe yarar. Saf Swift geliştirme için, Errorprotokole uyarak kendi hata örneğinizi oluşturmalısınız
Luca D'Alberti

@ LucaD'Alberti Çözümünüz sorunu çözdü, kabul edebilmem için yanıt olarak eklemekten çekinmeyin!
Rikh

Yanıtlar:


74

Şu LocalizedErrordeğerlerle Swift protokolüne uygun bir protokol oluşturabilirsiniz :

protocol OurErrorProtocol: LocalizedError {

    var title: String? { get }
    var code: Int { get }
}

Bu, aşağıdaki gibi somut hatalar oluşturmamızı sağlar:

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'u oluşturmak gerekli değildir, sadece CustomError'ın Hata'yı doğrudan uygulaması yeterlidir. b) bu ​​işe yaramaz (en azından Swift 3'te: localizedDescription asla çağrılmaz ve "İşlem tamamlanamadı" mesajı alırsınız.). Bunun yerine LocalizedError'ı uygulamanız gerekir; cevabımı gör.
prewett

@prewett Sadece fark ettim ama haklısın! LocalizedError'da errorDescription alanının uygulanması, aslında yukarıda açıklanan yöntemimi kullanmak yerine mesajı ayarlar. LocalizedTitle alanına da ihtiyacım olduğu için hala "OurErrorProtocol" paketleyicisini tutuyorum. Bunu belirttiğiniz için teşekkürler!
Harry Bloom

106

Sizin durumunuzda, hata, bir Errorörnek oluşturmaya çalışmanızdır .ErrorSwift 3, özel bir hatayı tanımlamak için kullanılabilen bir protokoldür. Bu özellik, özellikle saf Swift uygulamalarının farklı işletim sistemlerinde çalışması içindir.

İOS geliştirmede NSErrorsınıf hala kullanılabilir ve uyumludurError protokole .

Dolayısıyla, amacınız yalnızca bu hata kodunu yaymaksa, kolayca değiştirebilirsiniz.

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

ile

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

Aksi takdirde kontrol Sandeep Bhandari bireyin cevabını özel bir hata tipini nasıl oluşturulacağını dair


15
Sadece hatayı alıyorum: Error cannot be created because it has no accessible initializers.
Supertecnoboff

@AbhishekThapliyal, yorumunuzu biraz daha detaylandırır mısınız? Ne demek istediğini anlayamıyorum.
Luca D'Alberti

2
@ LucaD'Alberti Swift 4'te olduğu gibi Hata Nesnesi oluştururken erişilebilir başlatıcıları olmadığı için gösterme Hatası oluşturulamıyor.
Maheep

1
@Maheep cevabımda önerdiğim şey kullanmak değil Error, ama NSError. Elbette kullanmak Errorbir hata verir.
Luca D'Alberti

Hata protokoldür. Doğrudan örneklenemez.
slobodans

52

Hatalarla başa çıkmak için numaralandırmalar oluşturabilirsiniz :)

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

ve sonra http yanıt kodunu almak ve karşılığında karşılık gelen hatayı döndürmek için enum içinde bir yöntem oluşturun :)

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

Son olarak, RikhError türünde tek bir parametreyi kabul etmek için başarısızlık bloğunuzu güncelleyin :)

Swift3'ü burada https://learnwithmehere.blogspot.in kullanarak geleneksel Amaç - C tabanlı Nesne Yönelimli ağ modelini modern Protokol Odaklı modele yeniden yapılandırmaya dair ayrıntılı bir eğitimim var. Bir göz atın :)

Umarım yardımcı olur :)


Ahh ama bunun tüm vakaları elle halletmeme gerek yok mu? Hata kodlarını yazın mı?
Rikh

Evet, yapmanız gerekenler: D Ama aynı zamanda her bir hata durumuna özel çeşitli eylemler gerçekleştirebilirsiniz :) artık hata modeli üzerinde ince bir kontrole sahipsiniz, eğer yapmak istemiyorsanız 400 ... 404 numaralı durumu kullanabilirsiniz. {...} sadece genel vakaları ele alın :)
Sandeep Bhandari

Ahh evet! Teşekkürler
Rikh

Birden fazla http kodunun aynı durumu göstermesi gerekmediğini varsayarsak, sadece RikhError: Int, Error {case geçersizRequest = 400} numaralandırmalı ve sonra onu oluşturabilmelisiniz RikhError (rawValue: httpCode)
Brian F Leighty

51

NSError nesnesini kullanmalısınız.

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

Sonra NSError'ı Error nesnesine at


29

Detaylar

  • Xcode Sürümü 10.2.1 (10E1001)
  • Swift 5

Bir uygulamadaki hataları düzenleme çözümü

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

Kullanım

//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 uygula:

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

Örneğin, cevaplardan birinde açıklandığı gibi Hata'yı basitçe uygulamanın başarısız olacağını (en azından Swift 3'te) ve localizedDescription'ı çağırmanın "İşlem tamamlanamadı. (.StringError hatası 1.)" dizesiyle sonuçlanacağını unutmayın. "


Bu mMsg = msg olmalı mı
Brett

1
Oops, doğru. "Msg" yi "açıklama" olarak değiştirdim, umarım orijinalimden biraz daha nettir.
2017

4
Bunu kısaltabilirsiniz struct StringError : LocalizedError { public let errorDescription: String? }ve bu basitçeStringError(errorDescription: "some message")
Koen olarak kullanılabilir.

7
 let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error
            self.showLoginError(error)

bir NSError nesnesi oluşturun ve bunu Hata olarak yazın, her yerde gösterin

private func showLoginError(_ error: Error?) {
    if let errorObj = error {
        UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self)
    }
}

6

Hala Harry'nin cevabının en basit ve tamamlanmış olduğunu düşünüyorum, ancak daha basit bir şeye ihtiyacınız varsa, o zaman şunu kullanın:

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

Ve bunu şu şekilde kullanın veya test edin:

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

1

Zaten bir yanıttan memnun kaldığınızı biliyorum, ancak doğru yaklaşımı öğrenmekle ilgileniyorsanız, bu sizin için yardımcı olabilir. Hata nesnesindeki hata koduyla http yanıt hata kodunu karıştırmamayı tercih ederim (kafam karıştı mı? Lütfen biraz okumaya devam edin ...).

Http yanıt kodları, yanıt alındığında genel durumları tanımlayan ve 1xx ile 5xx arasında değişen bir http yanıtıyla ilgili standart hata kodlarıdır (ör. 200 OK, 408 İstek zaman aşımına uğradı, 504 Ağ geçidi zaman aşımı vb. - http://www.restapitutorial.com/ httpstatuscodes.html )

Bir NSError nesnesindeki hata kodu, nesnenin belirli bir uygulama / ürün / yazılım alanı için tanımladığı hata türüne çok özel bir tanımlama sağlar. Örneğin uygulamanız "Maalesef bu kaydı günde bir defadan fazla güncelleyemezsiniz" için 1000 kullanabilir veya etki alanınıza / uygulamanıza özel "Bu kaynağa erişmek için yönetici rolüne ihtiyacınız var" için 1001 diyebilir. mantık.

Çok küçük bir uygulama için bazen bu iki kavram birleştirilir. Ancak görebileceğiniz gibi tamamen farklıdırlar ve büyük yazılımlar tasarlamak ve bunlarla çalışmak için çok önemlidirler.

Bu nedenle, kodu daha iyi ele almak için iki teknik olabilir:

1. Tamamlama geri araması tüm kontrolleri gerçekleştirecektir

completionHandler(data, httpResponse, responseError) 

2. Yönteminiz başarı ve hata durumuna karar verir ve ardından karşılık gelen geri aramayı başlatır

if nil == responseError { 
   successCallback(data)
} else {
   failureCallback(data, responseError) // failure can have data also for standard REST request/response APIs
}

Mutlu kodlamalar :)


Yani temelde söylemeye çalıştığınız şey, sunucudan döndürülen belirli bir hata kodu durumunda görüntülenecek belirli bir dizge olması durumunda "veri" parametresini geçmek mi? (Üzgünüm, bazen biraz yavaş olabilirim!)
Rikh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.