Can I somehow do a synchronous HTTP request via NSURLSession in Swift
You can use this NSURLSession extension to add a synchronous method:
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:
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) }}
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
Updated one of the answers to use a URLRequest instead, so we can use PUT etc instead.
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 = bodyrequest.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.")}