[英]Swift array not filled in completion block
我试图追加数组(我知道一个简单的任务),但是由于某种原因我的数组为空。 不管我做什么。 这是我的工作:
我想计算总余额(我应该先做金额*价格,然后将其加总)。
所以我以为我会制作一个余额数组,然后将它们加起来,但数组为空:
func getBalances(completion: @escaping (_ balancesArray: [Double])->()){
var balancesArray = [Double]()
for f in portfolioArray{
getPrice(for: f.name!, in: "EUR", completion: { (price) in
balancesArray.append(f.amount * price)
//!!!!!!If I print here the array, it is full!!!!!!
})
}
completion(balancesArray)
}
这是getPrice函数(它返回了价格,我测试过):
func getPrice(for crypto: String, in fiat: String, completion: @escaping (_ price: Double)->()){
API.getCryptoRates(cryptoSymbol: crypto, fiatSymbol: fiat) { (error, response: [CurrencyResponse]?) in
if error == nil{
if let prices = response{
guard let p = Double(prices[0].price) else { return }
completion(p)
}
}
}
}
所以我的问题是,为什么它是空的? 如果我是正确的,那么完成应该具有填充数组。 而且不应该有任何线程问题。
有人可以引导我走上正确的道路吗? 任何回应表示赞赏!
getPrice
是异步的。 for
循环早在首次调用getPrice
之前getPrice
完成。
您需要使用DispatchGroup
来确保在对getPrice
所有调用都完成之前不对completion(balancesArray)
进行调用。 请参阅什么是最好的方法来遍历APi的结果,并知道何时完成? 举个例子
您还需要确保从单个线程追加到balancesArray
以避免并发写入。 请参阅快速创建线程安全数组以获取解决方案。
问题是getPrice
是异步的,因此当您调用completion
异步函数实际上尚未完成执行。 您可以使用DispatchGroup
解决您的问题。
您还应确保仅从单个线程写入balancesArray
,以避免并发问题。
下面的代码确保完成处理getBalances
一次,所有来电只叫getPrice
完成,但它不会使balancesArray
线程安全的,你可以照顾,由于在解释斯威夫特创建线程安全数组
func getBalances(completion: @escaping (_ balancesArray: [Double])->()){
var balancesArray = [Double]()
let group = DispatchGroup()
for f in portfolioArray{
group.enter()
getPrice(for: f.name!, in: "EUR", completion: { price in
if let p = price{
balancesArray.append(f.amount * p)
}
group.leave()
})
}
group.notify(queue: .main, execute: {
completion(balancesArray)
})
}
您的getPrice
函数有缺陷。 您需要确保在所有情况下都调用完成处理程序,即使结果是错误的也是如此。 处理网络请求时,应始终使完成处理程序返回可选值,并且在出现任何问题的情况下,应使用nil
值调用completion
。 如果您想知道使用nil
值的原因,还可以使您的闭包返回一个包含可选值和可选Error
的元组,例如URLSession.dataTask(with:, completionHandler:)
, URLSession.dataTask(with:, completionHandler:)
。
func getPrice(for crypto: String, in fiat: String, completion: @escaping (_ price: Double?)->()){
API.getCryptoRates(cryptoSymbol: crypto, fiatSymbol: fiat) { (error, response: [CurrencyResponse]?) in
if error == nil{
if let prices = response{
guard let p = Double(prices[0].price) else { completion(nil); return }
completion(p)
} else {
completion(nil)
}
} else {
completion(nil)
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.