ios Swift 2 上的同步 URL 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31557688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Synchronous URL request on Swift 2
提问by DuckDucking
I have this code from hereto do synchronous request of a URL on Swift 2.
我有这个代码从这里在 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)
}
but the function NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
was deprecated and I don't see how one can do synchronous requests on Swift, cause the alternative is asynchronous. Apparently Apple deprecated the only function that can do it synchronously.
但该函数NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
已被弃用,我不知道如何在 Swift 上执行同步请求,因为替代方案是异步的。显然,Apple 弃用了唯一可以同步执行的功能。
How can I do that?
我怎样才能做到这一点?
采纳答案by Jiri Trecak
There is a reason behind deprecation - there is just no use for it. You should avoid synchronous network requests as a plague. It has two main problems and only one advantage (it is easy to use.. but isn't async as well?):
弃用背后有一个原因 - 它没有用。您应该避免将同步网络请求视为瘟疫。它有两个主要问题,只有一个优点(它很容易使用......但不是异步的吗?):
- The request blocks your UI if not called from different thread, but if you do that, why don't use asynchronous handler right away?
- There is no way how to cancel that request except when it errors on its own
- 如果不是从不同的线程调用,请求会阻塞你的 UI,但如果你这样做,为什么不立即使用异步处理程序?
- 除非它自己出错,否则无法取消该请求
Instead of this, just use asynchronous request:
而不是这样,只需使用异步请求:
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 Deprecation
iOS9 弃用
Since in iOS9 this method is being deprecated, I suggest you to use NSURLSession instead:
由于在 iOS9 中此方法已被弃用,我建议您改用 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)
}
回答by fpg1503
If you reallywanna do it synchronously you can always use a semaphore:
如果你真的想同步做,你总是可以使用信号量:
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:Add some hackish ! so the code works, don't do this in production code
编辑:添加一些hackish!所以代码有效,不要在生产代码中这样做
Swift 3.0+ (3.0, 3.1, 3.2, 4.0)
斯威夫特 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: 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?)
}
}
, encoding: .utf8) } ?? ""
f(reply)
}
回答by Tom Andersen
Synchronous requests are sometimes fine on background threads. Sometimes you have a complicated, impossible to change code base full of async requests, etc. Then there is a small request that can't be folded into the current system as async. If the sync fails, then you get no data. Simple. It mimics how the file system works.
同步请求有时在后台线程上很好。有时你有一个复杂的、不可能改变的代码库,里面充满了异步请求等等。然后有一个小请求不能作为异步折叠到当前系统中。如果同步失败,则您不会获得任何数据。简单的。它模仿文件系统的工作方式。
Sure it does not cover all sorts of eventualities, but there are lots of eventualities not covered in async as well.
当然,它并没有涵盖所有可能发生的情况,但是异步中也没有涵盖很多可能发生的情况。
回答by Matej Ukmar
Based on @fpg1503 answer I made a simple extension in Swift 3:
基于@fpg1503 的回答,我在 Swift 3 中做了一个简单的扩展:
let (data, response) = try URLSession.shared.synchronousDataTask(with: request)
Then you simply call:
然后你只需调用:
##代码##