Demande d'URL synchrone sur Swift 2

J'ai ce code d' ici pour faire une requête synchrone d'une URL sur Swift 2.

func send(url: Ssortingng, f: (Ssortingng)-> ()) { var request = NSURLRequest(URL: NSURL(ssortingng: url)!) var response: NSURLResponse? var error: NSErrorPointer = nil var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error) var reply = NSSsortingng(data: data, encoding: NSUTF8SsortingngEncoding) 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 asynchronous. Apparemment, Apple a déprécié 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 – il n'y a juste aucune utilité pour cela. Vous devriez éviter les requests de réseau synchrones comme un fléau. Il a deux principaux problèmes et un seul avantage (il est facile à utiliser .. mais n'est pas asynchronous aussi bien?):

  • La requête bloque votre interface user si elle n'est pas appelée à partir d'un thread différent, mais si vous faites cela, pourquoi n'utilisez-vous pas le gestionnaire asynchronous tout de suite?
  • Il n'y a aucun moyen d'annuler cette requête, sauf si elle est elle-même une erreur

Au lieu de cela, utilisez simplement une requête asynchronous:

 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 = NSSsortingng(data: data, encoding: NSUTF8SsortingngEncoding) f(reply) }) 

iOS9 Déprécation

Puisque dans iOS9 cette méthode est dépréciée, je vous suggère d'utiliser NSURLSession à la place:

 let session = NSURLSession.sharedSession() session.dataTaskWithRequest(request) { (data, response, error) -> Void in // Handle incoming data like you would in synchronous request var reply = NSSsortingng(data: data, encoding: NSUTF8SsortingngEncoding) f(reply) } 

Si vous voulez vraiment le faire de manière synchrone, vous pouvez toujours utiliser un sémaphore:

 func send(url: Ssortingng, f: (Ssortingng) -> Void) { var request = NSURLRequest(URL: NSURL(ssortingng: 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 = NSSsortingng(data: data, encoding: NSUTF8SsortingngEncoding) f(reply) } 

EDIT: Ajouter un peu de hackish! donc le code fonctionne, ne le faites pas dans le code de production

Swift 3.0+ (3.0, 3.1, 3.2, 4.0)

 func send(url: Ssortingng, f: (Ssortingng) -> Void) { guard let url = URL(ssortingng: 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 { Ssortingng(data: $0, encoding: .utf8) } ?? "" f(reply) } 

Basé sur @ fpg1503 réponse, j'ai fait une simple extension dans 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 utiles sur les threads d'arrière-plan. Parfois, vous avez une base de code compliquée, impossible à changer, pleine de requêtes asynchronouss, etc. Ensuite, il y a une petite requête qui ne peut pas être repliée dans le système actuel comme asynchronous. Si la synchronisation échoue, vous n'obtenez aucune donnée. Simple. Il imite le fonctionnement du système de files.

Bien sûr, cela ne couvre pas toutes sortes d'éventualités, mais il y a beaucoup d'éventualités qui ne sont pas couvertes en async aussi bien.