Can I somehow do a synchronous HTTP request via NSURLSession
in Swift?
我能以某种方式在Swift中通过NSURLSession实现同步HTTP请求吗?
I can do an asynchronous request via the following code:
我可以通过以下代码进行异步请求:
if let url = NSURL(string: "https://2ch.hk/b/threads.json") {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {
(data, response, error) in
var jsonError: NSError?
let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as [String: AnyObject]
if jsonError != nil {
return
}
// ...
}
task.resume()
}
But what about synchronous request?
但是同步请求呢?
Thanks in advance.
提前谢谢。
4 个解决方案
#1
54
You can use this NSURLSession extension to add a synchronous method:
您可以使用这个NSURLSession扩展来添加同步方法:
extension NSURLSession {
func synchronousDataTaskWithURL(url: NSURL) -> (NSData?, NSURLResponse?, NSError?) {
var data: NSData?, response: NSURLResponse?, error: NSError?
let semaphore = dispatch_semaphore_create(0)
dataTaskWithURL(url) {
data = $0; response = $1; error = $2
dispatch_semaphore_signal(semaphore)
}.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return (data, response, error)
}
}
Update for Swift 3:
更新迅速3:
extension URLSession {
func synchronousDataTask(with url: URL) -> (Data?, URLResponse?, Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = self.dataTask(with: url) {
data = $0
response = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return (data, response, error)
}
}
#2
27
Apple thread discussing the same issue.
苹果线程也在讨论同样的问题。
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(__autoreleasing NSURLResponse **)responsePtr
error:(__autoreleasing NSError **)errorPtr {
dispatch_semaphore_t sem;
__block NSData * result;
result = nil;
sem = dispatch_semaphore_create(0);
[[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (errorPtr != NULL) {
*errorPtr = error;
}
if (responsePtr != NULL) {
*responsePtr = response;
}
if (error == nil) {
result = data;
}
dispatch_semaphore_signal(sem);
}] resume];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return result;
}
Answer by Quinn "The Eskimo!" Apple Developer Relations, Developer Technical Support, Core OS/Hardware
奎因的回答是“爱斯基摩人!”苹果开发者关系,开发者技术支持,核心OS/硬件
#3
8
Updated one of the answers to use a URLRequest instead, so we can use PUT etc instead.
更新其中一个答案以使用URLRequest代替,因此我们可以使用PUT等代替。
extension URLSession {
func synchronousDataTask(urlrequest: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = self.dataTask(with: urlrequest) {
data = $0
response = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return (data, response, error)
}
}
I'm calling like this.
我打电话是这样的。
var request = URLRequest(url: url1)
request.httpBody = body
request.httpMethod = "PUT"
let (_, _, error) = URLSession.shared.synchronousDataTask(urlrequest: request)
if let error = error {
print("Synchronous task ended with error: \(error)")
}
else {
print("Synchronous task ended without errors.")
}
#4
-2
Be careful with synchronous requests because it can result in bad user experience but I know sometimes its necessary. For synchronous requests use NSURLConnection:
对于同步请求要小心,因为它可能导致糟糕的用户体验,但我知道有时它是必要的。对于同步请求,使用NSURLConnection:
func synchronousRequest() -> NSDictionary {
//creating the request
let url: NSURL! = NSURL(string: "exampledomain/...")
var request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
var error: NSError?
var response: NSURLResponse?
let urlData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
error = nil
let resultDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
return resultDictionary
}
#1
54
You can use this NSURLSession extension to add a synchronous method:
您可以使用这个NSURLSession扩展来添加同步方法:
extension NSURLSession {
func synchronousDataTaskWithURL(url: NSURL) -> (NSData?, NSURLResponse?, NSError?) {
var data: NSData?, response: NSURLResponse?, error: NSError?
let semaphore = dispatch_semaphore_create(0)
dataTaskWithURL(url) {
data = $0; response = $1; error = $2
dispatch_semaphore_signal(semaphore)
}.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return (data, response, error)
}
}
Update for Swift 3:
更新迅速3:
extension URLSession {
func synchronousDataTask(with url: URL) -> (Data?, URLResponse?, Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = self.dataTask(with: url) {
data = $0
response = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return (data, response, error)
}
}
#2
27
Apple thread discussing the same issue.
苹果线程也在讨论同样的问题。
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(__autoreleasing NSURLResponse **)responsePtr
error:(__autoreleasing NSError **)errorPtr {
dispatch_semaphore_t sem;
__block NSData * result;
result = nil;
sem = dispatch_semaphore_create(0);
[[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (errorPtr != NULL) {
*errorPtr = error;
}
if (responsePtr != NULL) {
*responsePtr = response;
}
if (error == nil) {
result = data;
}
dispatch_semaphore_signal(sem);
}] resume];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return result;
}
Answer by Quinn "The Eskimo!" Apple Developer Relations, Developer Technical Support, Core OS/Hardware
奎因的回答是“爱斯基摩人!”苹果开发者关系,开发者技术支持,核心OS/硬件
#3
8
Updated one of the answers to use a URLRequest instead, so we can use PUT etc instead.
更新其中一个答案以使用URLRequest代替,因此我们可以使用PUT等代替。
extension URLSession {
func synchronousDataTask(urlrequest: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = self.dataTask(with: urlrequest) {
data = $0
response = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return (data, response, error)
}
}
I'm calling like this.
我打电话是这样的。
var request = URLRequest(url: url1)
request.httpBody = body
request.httpMethod = "PUT"
let (_, _, error) = URLSession.shared.synchronousDataTask(urlrequest: request)
if let error = error {
print("Synchronous task ended with error: \(error)")
}
else {
print("Synchronous task ended without errors.")
}
#4
-2
Be careful with synchronous requests because it can result in bad user experience but I know sometimes its necessary. For synchronous requests use NSURLConnection:
对于同步请求要小心,因为它可能导致糟糕的用户体验,但我知道有时它是必要的。对于同步请求,使用NSURLConnection:
func synchronousRequest() -> NSDictionary {
//creating the request
let url: NSURL! = NSURL(string: "exampledomain/...")
var request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
var error: NSError?
var response: NSURLResponse?
let urlData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
error = nil
let resultDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
return resultDictionary
}