如何检测到所有30个Alamofire请求都已得到响应? [英] How to detect that all 30 Alamofire requests have all been responded to?

查看:166
本文介绍了如何检测到所有30个Alamofire请求都已得到响应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个应用程序,通过在图表中显示数据来显示过去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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆