I am trying to do a synchronous request using Alamofire
. I have looked on Stackoverflow and found this question: making an asynchronous alamofire request synchronous.
I saw that the accepted answer uses completion
to make Alamofire
request synchronous but I cannot make it to work. This is my simplified code:
func loadData(completion: (Bool)) -> (Int, [String], [String], [String]){
Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let JSON = response.result.value as! [[String : AnyObject]]!{
//Here I retrieve the data
}
completion(true)
break
case .failure(_):
print("Error")
completion(false)
break
}
}
return (numberRows, nameArray, ageArray, birthdayArray)
}
With this code I am getting an error when trying to make completion(bool value)
. The error that I am getting is the following:
Cannot call value of non-function type 'Bool'
I have tried using a lot of examples using completion to get the values synchronously (because I need to retrieve the data before to show it on a table and at the same time get the number of rows of that table) without success.
How can I use that completion to get a synchronous response?
Thanks in advance!
Updated:
You can use a Semaphore to freeze the calling thread until the task has returned a value: Ref
func performSynchronously(request: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) {
let semaphore = DispatchSemaphore(value: 0)
var data: Data?
var response: URLResponse?
var error: Error?
let task = self.dataTask(with: request) {
data = $0
response = $1
error = $2
semaphore.signal()
}
task.resume()
semaphore.wait()
return (data, response, error)
}
Now, let’s say that we wanted to render the items loaded by the above WWDCItemsLoader within a SwiftUI view. An initial idea on how to do that might be to do something like this: Ref
struct WWDCItemsList: View {
var loader: WWDCItemsLoader
@State private var loadingState = LoadingState<[WWDCItem]>.idle
var body: some View {
switch loadingState {
case .idle:
Color.clear.onAppear(perform: loadItems)
case .loading:
ProgressView()
case .loaded(let items):
List(items) { item in
// Rendering each item
...
}
case .failed(let error):
ErrorView(error: error, reloadHandler: loadItems)
}
}
private func loadItems() async {
loadingState = .loading
do {
let items = try await loader.load()
loadingState = .loaded(items)
} catch {
loadingState = .failed(error)
}
}
}
Old Answer: (Swift 2.0)
when you use completion handler do not use return.
func loadData(completion: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ()){
Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let JSON = response.result.value as! [[String : AnyObject]]!{
//Here I retrieve the data
}
completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
break
case .failure(_):
print("Error")
completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
break
}
}
}
loadData (completion: { (number, strArr1, strArr2, strArr3) in
// do it
// for exapmple
self.number = number
self.strArr1 = strArr1
// and so on
})
or if you want return any value in closure you must use completion handler for return any value or some thing like, for example if you want return Boolean value:
func loadData(completion:(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray) -> (Bool))
and in the loadData
loadData( completion: { ( number, strArr1, strArr2, strArr3 ) -> (Bool) in
# code
return False
})
or some think else.
I use swift 3. but if you want another version of swift careful about External Parameter Names and internal parameter names, like: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ())
if you want set external parameter names, just need drop _
and set name for parameters.