To, co staram się osiągnąć, to wykonać URLSession
żądanie w swift 3. Wykonuję tę akcję w osobnej funkcji (aby nie pisać kodu osobno dla GET i POST) i zwracam URLSessionDataTask
i obsługuję sukces i niepowodzenie w domknięciach. Coś w ten sposób-
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!)
}
}
}
}
Nie chcę obsługiwać warunku błędu w tej funkcji i chcę wygenerować błąd przy użyciu kodu odpowiedzi i zwrócić ten błąd, aby obsłużyć go, gdziekolwiek ta funkcja jest wywoływana. Czy ktoś może mi powiedzieć, jak się do tego zabrać? A może nie jest to „szybki” sposób radzenia sobie w takich sytuacjach?
ios
swift3
nsurlsession
Rikh
źródło
źródło
NSError
zamiastError
w deklaracji (var errorTemp = NSError(...)
)Error
protokołemOdpowiedzi:
Możesz utworzyć protokół zgodny z
LocalizedError
protokołem Swift z następującymi wartościami:protocol OurErrorProtocol: LocalizedError { var title: String? { get } var code: Int { get } }
To pozwala nam tworzyć konkretne błędy, takie jak:
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 } }
źródło
W Twoim przypadku błąd polega na tym, że próbujesz wygenerować
Error
instancję.Error
w Swift 3 to protokół, którego można użyć do zdefiniowania niestandardowego błędu. Ta funkcja jest szczególnie przydatna dla czystych aplikacji Swift, które działają w różnych systemach operacyjnych.W rozwoju iOS
NSError
klasa jest nadal dostępna i jest zgodna zError
protokołem.Jeśli więc Twoim celem jest tylko propagowanie tego kodu błędu, możesz łatwo go zastąpić
var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
z
var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
W przeciwnym razie sprawdzić Sandeep Bhandari „s odpowiedzi dotyczące sposobu tworzenia niestandardowego typu błędu
źródło
Error cannot be created because it has no accessible initializers
.Error
, aleNSError
. Oczywiście użycieError
powoduje błąd.Możesz tworzyć wyliczenia, aby radzić sobie z błędami :)
enum RikhError: Error { case unknownError case connectionError case invalidCredentials case invalidRequest case notFound case invalidResponse case serverError case serverUnavailable case timeOut case unsuppotedURL }
a następnie utwórz metodę wewnątrz enum, aby otrzymać kod odpowiedzi http i zwrócić w odpowiedzi odpowiedni błąd :)
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 } }
Na koniec zaktualizuj blok błędów, aby akceptował pojedynczy parametr typu RikhError :)
Mam szczegółowy samouczek na temat restrukturyzacji tradycyjnego modelu sieci Objective opartego na C do nowoczesnego modelu zorientowanego na protokół przy użyciu Swift3 tutaj https://learnwithmehere.blogspot.in Spójrz :)
Mam nadzieję, że to pomoże :)
źródło
Powinieneś użyć obiektu NSError.
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invalid access token"])
Następnie rzuć NSError na obiekt Error
źródło
Detale
Rozwiązanie problemu organizacji błędów w aplikacji
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 } } }
Stosowanie
//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) }
źródło
Zaimplementuj 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 } }
Zwróć uwagę, że samo zaimplementowanie na przykład błędu, jak opisano w jednej z odpowiedzi, zakończy się niepowodzeniem (przynajmniej w języku Swift 3), a wywołanie localizedDescription spowoduje wyświetlenie ciągu „Operacja nie mogła zostać zakończona. (.StringError error 1.) "
źródło
struct StringError : LocalizedError { public let errorDescription: String? }
, a to po prostu użyj jakoStringError(errorDescription: "some message")
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error self.showLoginError(error)
utwórz obiekt NSError i typecast na Error, pokaż go w dowolnym miejscu
private func showLoginError(_ error: Error?) { if let errorObj = error { UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self) } }
źródło
Nadal uważam, że odpowiedź Harry'ego jest najprostsza i kompletna, ale jeśli potrzebujesz czegoś jeszcze prostszego, użyj:
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 } }
I użyj lub przetestuj w ten sposób:
printError(error: AppError(message: "My App Error!!!")) func print(error: Error) { print("We have an ERROR: ", error.localizedDescription) }
źródło
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) }
źródło
Wiem, że odpowiedź była już zadowalająca, ale jeśli chcesz poznać właściwe podejście, może to być pomocne. Wolałbym nie mieszać kodu błędu odpowiedzi http z kodem błędu w obiekcie błędu (zdezorientowany? Proszę kontynuować czytanie trochę ...).
Kody odpowiedzi http to standardowe kody błędów dotyczące odpowiedzi http definiujące ogólne sytuacje, w których otrzymywana jest odpowiedź, i wahają się od 1xx do 5xx (np. 200 OK, przekroczono limit czasu 408 żądania, przekroczono limit czasu bramy 504 itp. - http://www.restapitutorial.com/ httpstatuscodes.html )
Kod błędu w obiekcie NSError zapewnia bardzo dokładną identyfikację rodzaju błędu opisywanego przez obiekt dla określonej domeny aplikacji / produktu / oprogramowania. Na przykład Twoja aplikacja może używać 1000 dla „Przepraszamy, nie możesz aktualizować tego rekordu więcej niż raz dziennie” lub powiedzieć 1001 dla „Potrzebujesz roli menedżera, aby uzyskać dostęp do tego zasobu” ... które są specyficzne dla Twojej domeny / aplikacji logika.
W przypadku bardzo małej aplikacji czasami te dwa pojęcia są łączone. Ale są one zupełnie inne, jak widać, i są bardzo ważne i pomocne w projektowaniu i pracy z dużym oprogramowaniem.
Tak więc mogą istnieć dwie techniki lepszej obsługi kodu:
1. Wywołanie zwrotne zakończenia przeprowadzi wszystkie sprawdzenia
2. Twoja metoda decyduje o sukcesie i sytuacji błędu, a następnie wywołuje odpowiednie wywołanie zwrotne
if nil == responseError { successCallback(data) } else { failureCallback(data, responseError) // failure can have data also for standard REST request/response APIs }
Miłego kodowania :)
źródło