Swift 2上的同步URL请求
我从这里有这个代码做一个在Swift 2上的URL的同步请求。
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) }
但函数NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
已被弃用,我不明白如何可以在Swift上做同步请求,导致替代是asynchronous的。 显然苹果不赞成唯一的function,可以做到同步。
我怎样才能做到这一点?
有一个背后的原因 – 这是没有用的。 您应该避免同步networking请求作为瘟疫。 它有两个主要的问题,只有一个优势(它很容易使用,但不是asynchronous呢?):
- 如果不是从不同的线程调用,请求会阻塞你的UI,但是如果你这么做了,为什么不马上使用asynchronous处理呢?
- 除了自己的错误之外,没有办法取消这个请求
相反,只需使用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 = NSString(data: data, encoding: NSUTF8StringEncoding) f(reply) })
iOS9弃用
由于在iOS9中这个方法已被废弃,我build议你使用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) }
如果你真的想同步做,你可以使用信号量:
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) }
编辑:添加一些hackish! 所以代码工作,不要在生产代码中这样做
Swift 3.0+(3.0,3.1,3.2,4.0)
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) }
基于@ fpg1503答案我在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?) } }
那么你只需要打电话:
let (data, response) = try URLSession.shared.synchronousDataTask(with: request)
后台线程上的同步请求有时会很好。 有时你有一个复杂的,不可能改变充满asynchronous请求的代码库等。然后有一个小的请求,不能作为asynchronous折叠到当前系统。 如果同步失败,那么你得不到数据。 简单。 它模仿文件系统的工作方式。
当然,这并不包括各种可能性,但是还有很多事情不属于asynchronous。