Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何检测所有30个Alamofire请求都已响应?_Ios_Swift_Alamofire - Fatal编程技术网

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

Ios 如何检测所有30个Alamofire请求都已响应?,ios,swift,alamofire,Ios,Swift,Alamofire,我正在制作一个应用程序,通过在图表中显示数据来显示过去30天两种货币之间的汇率。我正在使用Alamofire和SwiftyJSON解析响应。我正在使用的API是 在我的视图控制器中,我有一个名为getRate的方法,它将填充一个名为rates的字典[Date:Double]。getRate将在viewDidLoad中调用,定义如下: func getRate() { let baseCurrency = UserDefaults.standard.string(forKey: "base

我正在制作一个应用程序,通过在图表中显示数据来显示过去30天两种货币之间的汇率。我正在使用Alamofire和SwiftyJSON解析响应。我正在使用的API是

在我的视图控制器中,我有一个名为getRate的方法,它将填充一个名为rates的字典[Date:Double]。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天中每天的日期。self.currency是由另一个视图控制器传递到此视图控制器的枚举类型值。self.currency.currencyCode是一个计算属性,返回枚举表示的货币的货币代码,例如GBP。基本上,getRate发出30个请求,并将响应值添加到rates字典中

我想做的是,在所有30个请求都得到无误响应后,根据汇率绘制一张图表。目前,我检查字典是否有30个条目。如果是,请刷新图表:

var rates: [Date: Double] = [:]
    {
    didSet {
        if rates.count == 30 {
            refreshCharts()
        }
    }
}
在我想添加刷新按钮之前,这一切都很好。当用户刷新时,我想再次发出相同的30个请求。若它们都成功且无误,则使用新值填充速率。如果发生一个或多个错误,我希望保持费率值不变,即保留旧数据

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


基本上,我如何知道所有30个请求何时得到响应以及是否出现任何错误?

您可以使用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
}
请注意,错误数组与字典的线程安全性不同

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

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

您可以对词典执行相同的操作

您可以使用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
}
请注意,错误数组与字典的线程安全性不同

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

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

你可以对你的字典做同样的操作

你能再解释一下线程安全吗?可能会发生什么?我编辑了答案以展示如何实现线程安全。基本上,如果您试图同时从多个队列写入变量,其中一些写入操作可能会被删除。在您的情况下,30个值中只有29个可以存在,即使所有网络请求都工作正常。好的,那么我应该在哪里将响应值分配给self.rates?在group.notify块中?但是我不能访问那里的响应,对吗?您应该在queue.async{}块中分配给self.rates。在group.notify块中,将正确填充rates和errors集合。您能再解释一下线程安全吗?可能会发生什么?我编辑了答案以展示如何实现线程安全。基本上,如果您试图同时从多个队列写入变量,其中一些写入操作可能会被删除。在您的情况下,30个值中只有29个可以存在,即使所有网络请求都工作正常。好的,那么我应该在哪里将响应值分配给self.rates?在group.notify块中?但是我不能访问那里的响应,对吗?您应该在queue.async{}块中分配给self.rates。在group.notify块中,将正确填充rates和errors集合