如何检测所有30个Alamofire请求都已响应?

时间:2017-04-12 10:15:45

标签: ios swift alamofire

我正在创建一个应用程序,通过在图表中显示数据,向您显示过去30天内两种货币之间的汇率。我正在使用Alamofire和SwiftyJSON来解析响应。我使用的API是http://fixer.io

在我的视图控制器中,我有一个名为getRate的方法,它将填充一个名为[Date: Double]的字典(rates)。 getRate将调用viewDidLoad,其定义如下:

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天内每天存储Dateself.currency是由另一个视图控制器传递给此视图控制器的枚举类型值。 self.currency.currencyCode是一个计算属性,它返回枚举所代表的货币的货币代码,例如"GBP"。基本上,getRate发出了30个请求,并将响应值添加到rates字典中。

我想要做的是在没有错误的情况下响应所有30个请求后,根据汇率绘制图表。目前,我检查字典是否有30个条目。如果是,请刷新图表:

var rates: [Date: Double] = [:]
    {
    didSet {
        if rates.count == 30 {
            refreshCharts()
        }
    }
}

这个工作正常,直到我想添加"刷新"按钮。当用户刷新时,我想再次发出相同的30个请求。如果它们都成功且没有错误,请使用新值填充rates。如果发生一个或多个错误,我希望保持rates的值不变,即保留旧数据。

要做到这一点,我必须知道所有30个请求何时被响应以及是否有任何错误。我不能再使用if rates.count == 30技巧了,因为当用户刷新时,rates已经填充了旧值。我无法在开头将rates设置为空,因为这会丢失旧数据,当出现任何错误时需要显示旧数据。我无法保证在getRate开头没有错误。

基本上,如何知道何时响应所有30个请求以及是否发生错误

1 个答案:

答案 0 :(得分:4)

您可以使用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
}

请注意,errors数组不是线程安全的(与字典相同)。

编辑:为了线程安全,您可以在队列上调度更新,以确保不会立即从不同的线程修改变量。

let queue = DispatchQueue(label: "queue")
var errors: [Error] = []
for date in last30Days {
    // ...
    queue.async {
        errors.append(error)
    }
    // ...
}

你可以为你的词典做同样的事情