O que estou tentando fazer é executar uma URLSession
solicitação em swift 3. Estou executando essa ação em uma função separada (de modo a não escrever o código separadamente para GET e POST) e retornar URLSessionDataTask
e lidar com o sucesso e a falha nos fechamentos. Mais ou menos assim-
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!)
}
}
}
}
Não desejo manipular a condição de erro nesta função e desejo gerar um erro usando o código de resposta e retornar este Erro para manipulá-lo de onde quer que esta função seja chamada. Alguém pode me dizer como fazer isso? Ou não é essa a maneira "rápida" de lidar com essas situações?
ios
swift3
nsurlsession
Rikh
fonte
fonte
NSError
vez deError
na declaração (var errorTemp = NSError(...)
)Error
protocoloRespostas:
Você pode criar um protocolo, em conformidade com o
LocalizedError
protocolo Swift , com estes valores:protocol OurErrorProtocol: LocalizedError { var title: String? { get } var code: Int { get } }
Isso nos permite criar erros concretos como:
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 } }
fonte
No seu caso, o erro é que você está tentando gerar uma
Error
instância.Error
em Swift 3 é um protocolo que pode ser usado para definir um erro personalizado. Esse recurso é especialmente para aplicativos Swift puros para rodar em sistemas operacionais diferentes.No desenvolvimento iOS, a
NSError
classe ainda está disponível e está em conformidade com oError
protocolo.Portanto, se o seu objetivo é apenas propagar este código de erro, você pode facilmente substituir
var errorTemp = Error(domain:"", code:httpResponse.statusCode, userInfo:nil)
com
var errorTemp = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
Caso contrário, verifique a Sandeep Bhandari 's resposta a respeito de como criar um tipo de erro personalizada
fonte
Error cannot be created because it has no accessible initializers
.Error
, masNSError
. É claro que usarError
gera um erro.Você pode criar enums para lidar com erros :)
enum RikhError: Error { case unknownError case connectionError case invalidCredentials case invalidRequest case notFound case invalidResponse case serverError case serverUnavailable case timeOut case unsuppotedURL }
e, em seguida, crie um método dentro de enum para receber o código de resposta http e retornar o erro correspondente em retorno :)
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 } }
Por fim, atualize seu bloco de falha para aceitar um parâmetro único do tipo RikhError :)
Eu tenho um tutorial detalhado sobre como reestruturar o modelo tradicional de rede Objective-C baseado em Object Oriented para o modelo moderno de Protocol Oriented usando Swift3 aqui https://learnwithmehere.blogspot.in Dê uma olhada :)
Espero que ajude :)
fonte
Você deve usar o objeto NSError.
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invalid access token"])
Em seguida, lance NSError para o objeto Error
fonte
Detalhes
Solução de erros de organização em um aplicativo
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 } } }
Uso
//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) }
fonte
Implementar 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 } }
Observe que simplesmente implementar Error, por exemplo, conforme descrito em uma das respostas, irá falhar (pelo menos no Swift 3) e chamar localizedDescription resultará na string "A operação não pôde ser concluída. (.StringError erro 1.) "
fonte
struct StringError : LocalizedError { public let errorDescription: String? }
, e simplesmente usar comoStringError(errorDescription: "some message")
let error = NSError(domain:"", code:401, userInfo:[ NSLocalizedDescriptionKey: "Invaild UserName or Password"]) as Error self.showLoginError(error)
crie um objeto NSError e digite-o para Erro, mostre-o em qualquer lugar
private func showLoginError(_ error: Error?) { if let errorObj = error { UIAlertController.alert("Login Error", message: errorObj.localizedDescription).action("OK").presentOn(self) } }
fonte
Ainda acho que a resposta de Harry é a mais simples e completa, mas se você precisar de algo ainda mais simples, use:
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 } }
E use ou teste assim:
printError(error: AppError(message: "My App Error!!!")) func print(error: Error) { print("We have an ERROR: ", error.localizedDescription) }
fonte
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) }
fonte
Sei que você já ficou satisfeito com a resposta, mas se estiver interessado em saber a abordagem certa, isso pode ser útil para você. Eu preferiria não misturar o código de erro de resposta http com o código de erro no objeto de erro (confuso? Continue lendo um pouco ...).
Os códigos de resposta http são códigos de erro padrão sobre uma resposta http que definem situações genéricas quando a resposta é recebida e varia de 1xx a 5xx (por exemplo, 200 OK, 408 Request time out, 504 Gateway timeout etc - http://www.restapitutorial.com/ httpstatuscodes.html )
O código de erro em um objeto NSError fornece uma identificação muito específica para o tipo de erro que o objeto descreve para um determinado domínio de aplicativo / produto / software. Por exemplo, seu aplicativo pode usar 1000 para "Desculpe, você não pode atualizar este registro mais de uma vez por dia" ou 1001 para "Você precisa da função de gerente para acessar este recurso" ... que são específicos para seu domínio / aplicativo lógica.
Para um aplicativo muito pequeno, às vezes esses dois conceitos são mesclados. Mas eles são completamente diferentes, como você pode ver, e muito importantes e úteis para projetar e trabalhar com softwares grandes.
Portanto, pode haver duas técnicas para lidar com o código da melhor maneira:
1. O retorno de chamada de conclusão executará todas as verificações
2. Seu método decide o sucesso e a situação de erro e, em seguida, invoca o retorno de chamada correspondente
if nil == responseError { successCallback(data) } else { failureCallback(data, responseError) // failure can have data also for standard REST request/response APIs }
Boa codificação :)
fonte