如何检测到所有30个Alamofire请求都已得到响应? [英] How to detect that all 30 Alamofire requests have all been responded to?
问题描述
我正在制作一个应用程序,通过在图表中显示数据来显示过去30天两种货币之间的汇率。我正在使用Alamofire和SwiftyJSON来解析响应。我使用的API是 http://fixer.io 。
I am making an app that shows you the exchange rates between two currencies in the last 30 days by presenting the data in a chart. I am using Alamofire, together with SwiftyJSON to parse the response. The API that I am using is http://fixer.io.
在我的视图控制器中,我有一个称为 getRate
的方法,该方法将填充字典( [Date:Double]
)称为 rates
。 getRate
将在 viewDidLoad
中调用,其定义如下:
In my view controller, I have this method called getRate
that will populate a dictionary ([Date: Double]
) called rates
. getRate
will be called in viewDidLoad
and is defined as follows:
func getRate() {
let baseCurrency = UserDefaults.standard.string(forKey: "baseCurrency")
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
for date in last30Days {
let dateString = formatter.string(from: date)
let url = "https://api.fixer.io/\(dateString)?base=\(baseCurrency!)&symbols=\(self.currency!)"
Alamofire.request(url).responseString {
[weak self]
response in
if let _ = response.error {
return
}
let json = JSON(parseJSON: response.value!)
if let _ = json["error"].string {
return
}
if self != nil {
if let rate = json["rates"][self!.currency.currencyCode].double {
self!.rates[date] = rate
}
}
}
}
}
last30Days
是一个常量,类型为 [Date]
,在过去30天内每天存储一个日期
。 self.currency
是另一个视图控制器传递给此视图控制器的枚举类型值。 self.currency.currencyCode
是一个计算得出的属性,它返回枚举表示的货币的货币代码,例如 GBP
。基本上, getRate
发出30个请求,并将响应值添加到 rates
字典中。
last30Days
is a constant, of type [Date]
, storing a Date
for every day in the last 30 days. self.currency
is a enum type value passed to this view controller by another view controller. self.currency.currencyCode
is a computed property that returns the currency code of the currency represented by the enum, e.g. "GBP"
. Basically, getRate
is making 30 requests and adding the responses values to the rates
dictionary.
我想做的是在所有30个请求均得到正确响应后,根据汇率绘制了一个图表。目前,我检查字典中是否有30个条目。如果有,请刷新图表:
What I want to do is after all 30 requests have been responded without an error, a chart is plotted according to the exchange rates. Currently, I check if the dictionary has 30 entries. If it does, refresh the chart:
var rates: [Date: Double] = [:]
{
didSet {
if rates.count == 30 {
refreshCharts()
}
}
}
在我要添加刷新按钮之前,此方法工作正常。当用户刷新时,我想再次发出相同的30个请求。如果它们全部成功且没有错误,请使用新值填充 rates
。如果发生一个或多个错误,我想保持 rates
的值不变,即保持旧数据。
This worked fine until I want to add a "refresh" button. When the user refreshes, I want to make the same 30 requests again. If they all succeed without error, populate rates
with the new values. If one or more error occurred, I want to keep the value of rates
unchanged i.e. keep the old data.
为此,我必须知道何时响应了所有30个请求,以及是否有任何错误。我不能再使用 if rates.count == 30
的技巧,因为当用户刷新时,比率
已经填充旧值。我一开始不能将 rates
设置为空,因为这会丢失旧数据,有任何错误时都需要显示该数据。我不能保证在 getRate
开始不会出现错误。
To do this, I must know when all 30 requests have been responded to and whether is any error. I can't use the if rates.count == 30
trick anymore because when the user refreshes, rates
is already populated with old values. I can't set rates
to empty at the beginning because that will lose the old data, which is needed to be displayed when there is any error. I can't guarantee that will be no errors at the start of getRate
.
基本上,如何我可以知道何时响应了全部30个请求以及是否发生了任何错误?
推荐答案
您可以使用DispatchGroup :
You can use a DispatchGroup:
let group = DispatchGroup()
var errors: [Error] = []
for date in last30Days {
group.enter()
// ...
Alamofire.request(url).responseString {
defer { group.leave() }
guard let error = response.error else {
errors.append(error)
return
}
// ...
}
}
group.notify(queue: .main) {
// All requests are finished now
}
请注意,错误数组将不是线程安全的(与您的字典相同)。
Please note that the errors array will not be thread safe (same as your dictionary).
编辑:为了线程安全,您可以在以下位置分派更新
For thread safety, you can dispatch your updates on a queue to ensure the variables aren't modified from different threads at once.
let queue = DispatchQueue(label: "queue")
var errors: [Error] = []
for date in last30Days {
// ...
queue.async {
errors.append(error)
}
// ...
}
您可以为字典做同样的事情
You can do the same for your dictionary
这篇关于如何检测到所有30个Alamofire请求都已得到响应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!