[英]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.