如何使用 Alamofire 发出同步请求?
How to make a synchronous request using Alamofire?
我正在尝试使用 Alamofire
进行同步请求。我查看了 Whosebug 并发现了这个问题:.
我看到接受的答案使用 completion
使 Alamofire
请求同步,但我无法使其工作。这是我的简化代码:
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)
}
使用此代码,我在尝试制作 completion(bool value)
时遇到错误。我收到的错误如下:
Cannot call value of non-function type 'Bool'
我已经尝试使用很多使用完成的示例来同步获取值(因为我需要在 table 上显示它之前检索数据,同时获取行数table) 没有成功。
如何使用该完成来获得同步响应?
提前致谢!
请注意,Apple 强烈反对发出同步请求,原因已注明 。
在这个例子中我简化了调用,如果你有更多的信息,比如单元格的内容,我建议你看一下SwiftyJSON和return整个JSON Blob,然后在相关方法(numberOfRows等)中解析它。
class TableViewJSONAsynchCalls: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView = UITableView()
var numberOfRows = 0;
override func viewDidLoad() {
loadData { (didCompleteRequest) in
if (didCompleteRequest) {
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
} else {
// Handle error if data was not loaded correctly
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfRows;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected")
}
func loadData(completion: (Bool) -> Void) {
// Make asynchronous call using alamofire
// This simulates you parsing the JSON and setting the relevant variables,
// personally I would recommend you return a JSON blob and then
// parse it in the relevant methods.
sleep(2)
// If call is successful
self.numberOfRows = 10
completion(true)
}
}
更新:
您可以使用信号量来冻结调用线程,直到任务 returned 值: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 = [=10=]
response =
error =
semaphore.signal()
}
task.resume()
semaphore.wait()
return (data, response, error)
}
现在,假设我们想要在 SwiftUI 视图中呈现由上述 WWDCItemsLoader 加载的项目。关于如何做到这一点的初步想法可能是做这样的事情: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)
}
}
}
旧答案:(Swift 2.0)
当你使用完成处理程序时不要使用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
})
或者如果你想要 return 闭包中的任何值,你必须使用 return 任何值或类似的完成处理程序,例如,如果你想要 return 布尔值:
func loadData(completion:(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray) -> (Bool))
并在 loadData
loadData( completion: { ( number, strArr1, strArr2, strArr3 ) -> (Bool) in
# code
return False
})
或者有些人不这么认为。
我使用 swift 3. 但是如果你想要另一个版本的 swift 请注意外部参数名称和内部参数名称,例如:@escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ())
如果你想设置外部参数名称,只需要删除 _
并为参数设置名称。
您可以使用如下方式将任何方法转换为同步方法:
func getName() -> (String?, Error?) { //an async call is in there
let semaphore = DispatchSemaphore(value: 0)
var name: String? // result to return
var error: Error? // error to throw
service.getUserName().subscribe { result in //call alamofire or anything
switch(result) {
case .success(let res): name = res.name
case .failure(let err): error = err
}
} onFailure: { err in
error = err
}.disposed(by: bag)
semaphore.wait()
return (name, error)
}
我正在尝试使用 Alamofire
进行同步请求。我查看了 Whosebug 并发现了这个问题:
我看到接受的答案使用 completion
使 Alamofire
请求同步,但我无法使其工作。这是我的简化代码:
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)
}
使用此代码,我在尝试制作 completion(bool value)
时遇到错误。我收到的错误如下:
Cannot call value of non-function type 'Bool'
我已经尝试使用很多使用完成的示例来同步获取值(因为我需要在 table 上显示它之前检索数据,同时获取行数table) 没有成功。
如何使用该完成来获得同步响应?
提前致谢!
请注意,Apple 强烈反对发出同步请求,原因已注明
在这个例子中我简化了调用,如果你有更多的信息,比如单元格的内容,我建议你看一下SwiftyJSON和return整个JSON Blob,然后在相关方法(numberOfRows等)中解析它。
class TableViewJSONAsynchCalls: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView = UITableView()
var numberOfRows = 0;
override func viewDidLoad() {
loadData { (didCompleteRequest) in
if (didCompleteRequest) {
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
} else {
// Handle error if data was not loaded correctly
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfRows;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected")
}
func loadData(completion: (Bool) -> Void) {
// Make asynchronous call using alamofire
// This simulates you parsing the JSON and setting the relevant variables,
// personally I would recommend you return a JSON blob and then
// parse it in the relevant methods.
sleep(2)
// If call is successful
self.numberOfRows = 10
completion(true)
}
}
更新:
您可以使用信号量来冻结调用线程,直到任务 returned 值: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 = [=10=]
response =
error =
semaphore.signal()
}
task.resume()
semaphore.wait()
return (data, response, error)
}
现在,假设我们想要在 SwiftUI 视图中呈现由上述 WWDCItemsLoader 加载的项目。关于如何做到这一点的初步想法可能是做这样的事情: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)
}
}
}
旧答案:(Swift 2.0)
当你使用完成处理程序时不要使用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
})
或者如果你想要 return 闭包中的任何值,你必须使用 return 任何值或类似的完成处理程序,例如,如果你想要 return 布尔值:
func loadData(completion:(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray) -> (Bool))
并在 loadData
loadData( completion: { ( number, strArr1, strArr2, strArr3 ) -> (Bool) in
# code
return False
})
或者有些人不这么认为。
我使用 swift 3. 但是如果你想要另一个版本的 swift 请注意外部参数名称和内部参数名称,例如:@escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ())
如果你想设置外部参数名称,只需要删除 _
并为参数设置名称。
您可以使用如下方式将任何方法转换为同步方法:
func getName() -> (String?, Error?) { //an async call is in there
let semaphore = DispatchSemaphore(value: 0)
var name: String? // result to return
var error: Error? // error to throw
service.getUserName().subscribe { result in //call alamofire or anything
switch(result) {
case .success(let res): name = res.name
case .failure(let err): error = err
}
} onFailure: { err in
error = err
}.disposed(by: bag)
semaphore.wait()
return (name, error)
}