J'ai le code suivant:
func completeLoadAction(urlString:String) -> Int {
let url = URL(string:urlString.trimmingCharacters(in: .whitespaces))
let request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
let ac = UIAlertController(title: "Unable to complete", message: "The load has been added to the completion queue. This will be processed once there is a connection.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
return
}
let httpStatus = response as? HTTPURLResponse
var httpStatusCode:Int = (httpStatus?.statusCode)!
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
let ac = UIAlertController(title: "Completed Successfully", message: "The "+coldel+" has been completed successfully", preferredStyle: .alert)
ac.addAction(UIAlertAction(title:"Continue", style: .default, handler: { action in self.performSegue(withIdentifier: "segueConfirmedLoad", sender: self) }))
self.present(ac, animated: true)
}
task.resume()
return httpStatusCode
}
Je dois pouvoir l'appeler et en même temps vérifier la valeur de retour car c'est le code d'état http, il me fera savoir si l'appel a réussi ou non.
Le problème est parce que c'est dans une tâche de données, je ne peux pas accéder au code d'état des réponses ici
var httpStatusCode:Int = (httpStatus?.statusCode)!
Parce que la tâche ne démarre pas tant que Task.Resume () n'est pas appelée et la tâche est asynchrone donc elle ne fonctionnera jamais.
Y a-t-il des moyens de contourner cela?
Il existe toujours un moyen d'utiliser le modèle asynchrone.
Pour rendre la fonction asynchrone, ajoutez un bloc d'achèvement
func completeLoadAction(urlString:String, completion: (Int) -> ()) {
let url = URL(string:urlString.trimmingCharacters(in: .whitespaces))
let request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
DispatchQueue.main.async {
let ac = UIAlertController(title: "Unable to complete", message: "The load has been added to the completion queue. This will be processed once there is a connection.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
completion(0) // or return an error code
return
}
let httpStatus = response as? HTTPURLResponse
var httpStatusCode:Int = (httpStatus?.statusCode)!
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
DispatchQueue.main.async {
let ac = UIAlertController(title: "Completed Successfully", message: "The "+coldel+" has been completed successfully", preferredStyle: .alert)
ac.addAction(UIAlertAction(title:"Continue", style: .default, handler: { action in self.performSegue(withIdentifier: "segueConfirmedLoad", sender: self) }))
self.present(ac, animated: true)
}
completion(httpStatusCode)
}
task.resume()
}
et l'appelle ainsi
completeLoadAction(urlString: "www.something.com") { code in
print(code)
}
Pour le rendre synchrone et attendre, vous pouvez utiliser des sémaphores comme ci-dessous
struct Login {
static func execute() -> Bool {
let request = NSURLRequest....
var success = false
let semaphore = DispatchSemaphore(value: 0)
let task = URLSession.shared.dataTask(with: request, completionHandler: { _, response, error in
if let error = error {
print("Error while trying to re-authenticate the user: \(error)")
} else if let response = response as? HTTPURLResponse,
300..<600 ~= response.statusCode {
print("Error while trying to re-authenticate the user, statusCode: \(response.statusCode)")
} else {
success = true
}
semaphore.signal()
})
task.resume()
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
return success
}
}
Cela ne fonctionnera pas dans toutes les situations. Supposons que vous implémentez une extension partagée. Et vous remplacez la méthode isContentValid()
qui retourne un booléen (vrai si le contenu est valide) ... mais afin de tester si le contenu est valide, vous voulez vérifier que le serveur est en cours d'exécution (ce est un exemple artificiel). Si vous effectuez un appel http asynchrone - bloc d'achèvement ou non - vous ne pouvez pas renvoyer la valeur appropriée du booléen; la seule façon d'y parvenir est de faire un appel synchrone et de renvoyer vrai/faux en fonction de la valeur de retour.
La réponse qui a publié le modèle de sémaphore est la bonne à utiliser dans ce cas.