J'ai ce code de ici pour faire une demande synchrone d'une URL sur Swift 2.
func send(url: String, f: (String)-> ()) {
var request = NSURLRequest(URL: NSURL(string: url)!)
var response: NSURLResponse?
var error: NSErrorPointer = nil
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
mais la fonction NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
était obsolète et je ne vois pas comment on peut faire des requêtes synchrones sur Swift, car l'alternative est asynchrone. Apparemment Apple a déconseillé la seule fonction qui peut le faire de manière synchrone.
Comment puis je faire ça?
Il y a une raison derrière la dépréciation - elle est tout simplement inutile. Vous devez éviter les demandes de réseau synchrone comme un fléau. Il a deux problèmes principaux et un seul avantage (il est facile à utiliser .. mais n'est-il pas aussi asynchrone?):
Au lieu de cela, utilisez simplement une demande asynchrone:
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
})
Dépréciation iOS9
Étant donné que dans iOS9, cette méthode est obsolète, je vous suggère d'utiliser plutôt NSURLSession:
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
Si vous vraiment voulez le faire de manière synchrone, vous pouvez toujours utiliser un sémaphore:
func send(url: String, f: (String) -> Void) {
var request = NSURLRequest(URL: NSURL(string: url)!)
var error: NSErrorPointer = nil
var data: NSData
var semaphore = dispatch_semaphore_create(0)
try! NSURLSession.sharedSession().dataTaskWithRequest(request) { (responseData, _, _) -> Void in
data = responseData! //treat optionals properly
dispatch_semaphore_signal(semaphore)
}.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
EDIT: Ajoutez un peu de hackish! pour que le code fonctionne, ne le faites pas dans le code de production
func send(url: String, f: (String) -> Void) {
guard let url = URL(string: url) else {
print("Error! Invalid URL!") //Do something else
return
}
let request = URLRequest(url: url)
let semaphore = DispatchSemaphore(value: 0)
var data: Data? = nil
URLSession.shared.dataTask(with: request) { (responseData, _, _) -> Void in
data = responseData
semaphore.signal()
}.resume()
semaphore.wait(timeout: .distantFuture)
let reply = data.flatMap { String(data: $0, encoding: .utf8) } ?? ""
f(reply)
}
Sur la base de la réponse @ fpg1503, j'ai fait une extension simple en Swift 3:
extension URLSession {
func synchronousDataTask(with request: URLRequest) throws -> (data: Data?, response: HTTPURLResponse?) {
let semaphore = DispatchSemaphore(value: 0)
var responseData: Data?
var theResponse: URLResponse?
var theError: Error?
dataTask(with: request) { (data, response, error) -> Void in
responseData = data
theResponse = response
theError = error
semaphore.signal()
}.resume()
_ = semaphore.wait(timeout: .distantFuture)
if let error = theError {
throw error
}
return (data: responseData, response: theResponse as! HTTPURLResponse?)
}
}
Ensuite, vous appelez simplement:
let (data, response) = try URLSession.shared.synchronousDataTask(with: request)
Les requêtes synchrones sont parfois correctes sur les threads d'arrière-plan. Parfois, vous avez une base de code compliquée, impossible à changer, pleine de demandes asynchrones, etc. Ensuite, il y a une petite demande qui ne peut pas être pliée dans le système actuel comme async. Si la synchronisation échoue, vous n'obtenez aucune donnée. Facile. Il imite le fonctionnement du système de fichiers.
Bien sûr, cela ne couvre pas toutes sortes d'éventualités, mais il existe également de nombreuses éventualités non couvertes par l'async.