Generally HTTP Requests are processed asynchronously, but sometimes we need them to be processed synchronously. However, URLSession
and Alamofire do not provide synchronous methods.
Since they only provide asynchronous methods, we can only wrap asynchronous methods to synchronous methods. The trick is to use a semaphore to wait for HTTP Requests finished.
func syncRequest(_ url: String, method: Method) -> (Data?, Error?) { var data: Data? var error: Error? let url = URL(string: url)! var request = URLRequest(url: url) request.httpMethod = method.rawValue let semaphore = DispatchSemaphore(value: 0) let dataTask = URLSession.shared.dataTask(with: request) { data = $0 error = $2 semaphore.signal() } dataTask.resume() _ = semaphore.wait(timeout: .distantFuture) return (data, error) }
1 comment
Question: how would you write this is if you want only two requests at a time when you have multiple requests going from different parts of the app.
My think would be this
let semaphore = DispatchSemaphore(value: 2) //two request
func syncRequest(_ url: String, method: Method) -> (Data?, Error?) {
var data: Data?
var error: Error?
let url = URL(string: url)!
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
let dataTask = URLSession.shared.dataTask(with: request) {
data = $0
error = $2
semaphore.signal()
}
_ = semaphore.wait(timeout: .distantFuture)
dataTask.resume() // this the resource we want to protect
return (data, error)
}
// Run on a global parallel queue
Global (..).async {syncRequest()}
Sadly this doesn’t work as expected…