我有一个tableView控制器,其中每一行将代表特定加密货币的值。我为用户想要跟踪的每种不同的加密货币提供了一个类,称为CryptoCurrency
。在TableView CellforRowAt
函数下,我调用了另一个名为getCryptoData的函数,该函数将使用AlamoFire发送api请求以获取每种加密货币的价格。
问题是cellForRowAt
函数在getCryptoData函数可以完成并更新模型之前返回默认价格为0.00的单元格。
我假设这是因为该函数异步运行吗?
如何使它在返回单元格之前等待函数完成,还是在完成后重新加载单元格?
我尝试在tableView.reloaddata()
函数的末尾添加updateCryptoData
,但这导致了无限循环。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CryptoCurrencyCell", for: indexPath)
let cryptoCurrencyItem = cryptoCurrencyContainer.listOfCryptoCurrencies[indexPath.row]
getCryptoData(url: getApiString(for: cryptoCurrencyItem.id), currencyItem: cryptoCurrencyItem)
cell.textLabel?.text = cryptoCurrencyContainer.listOfCryptoCurrencies[indexPath.row].name + "\(cryptoCurrencyItem.currentPrice)"
print(cryptoCurrencyItem.currentPrice)
return cell
}
func getCryptoData(url: String, currencyItem: CryptoCurrency) {
Alamofire.request(url, method: .get).responseJSON {
response in
if response.result.isSuccess {
print("Sucess! bitcoin data")
let cryptoDataJSON : JSON = JSON(response.result.value!)
print(cryptoDataJSON)
self.updateCryptoData(json: cryptoDataJSON, currencyItem: currencyItem)
} else {
print("oops")
print("Error: \(String(describing: response.result.error))")
//self.bitcoinPriceLabel.text = "Connection Issues"
}
}
}
func updateCryptoData(json : JSON, currencyItem: CryptoCurrency) {
if let cryptoPriceResult = json["ask"].double {
//bitcoinPriceLabel.text = String(bitcoinResult)
currencyItem.updatePrice(price: cryptoPriceResult)
print(currencyItem.currentPrice)
} else {
//bitcoinPriceLabel.text = "Price Unavailable"
print("something aint right")
}
}
在cellForRowAt
函数下,有一个打印语句:
print(cryptoCurrencyItem.currentPrice)
在单元返回之前捕获当前价格。控制台显示仍为0.00,表示getCryptoData函数尚未完成运行。
答案 0 :(得分:0)
可能不是最佳解决方案,但您可以将单元格传递给方法
func getCryptoData(url: String, currencyItem: CryptoCurrency, for cell: UITableViewCell) {
Alamofire.request(url, method: .get).responseJSON {
response in
if response.result.isSuccess {
print("Sucess! bitcoin data")
let cryptoDataJSON : JSON = JSON(response.result.value!)
print(cryptoDataJSON)
self.updateCryptoData(json: cryptoDataJSON, currencyItem: currencyItem, for: cell)
} else {
print("oops")
print("Error: \(String(describing: response.result.error))")
//self.bitcoinPriceLabel.text = "Connection Issues"
}
}
}
func updateCryptoData(json : JSON, currencyItem: CryptoCurrency, for cell: UITableViewCell) {
if let cryptoPriceResult = json["ask"].double {
//bitcoinPriceLabel.text = String(bitcoinResult)
currencyItem.updatePrice(price: cryptoPriceResult)
print(currencyItem.currentPrice)
cell.textLabel?.text = "\(cryptoPriceResult)" // your cell
} else {
//bitcoinPriceLabel.text = "Price Unavailable"
cell.textLabel?.text = "\(cryptoPriceResult)" // your cell
print("something aint right")
}
}
由于UITableViewCell
是引用类型,因此异步调用完成后,它将更新单元格文本标签。
答案 1 :(得分:0)
您的请求正在后台线程中运行。这意味着tableView在从请求获取数据之前运行。因此,当您在ValueTask<TResult>
方法中获得成功时,应在主线程中调用updateCryptoData
。
tableView.reloadData()
此代码将运行tableView cellForRow方法
答案 2 :(得分:0)
是的,在updateCryptoData函数末尾的tableView.reloaddata()将导致无限循环,因为在api调用后的每次重载中,您再次调用api并继续循环。
通过多种方法之一,您可以具有基于键值的数据结构。
在cellForRowAt函数中,如果标签可用,则将从数据结构中分配值。如果您的数据结构中没有可用的值,则显示一些默认值,例如“ loading”或微小的加载轮UI。
cell.priceLabel?.text = dataStructre["key"]
现在,此密钥可能是您用来标识货币项目的唯一ID。
在从单元格调用api之前,请预先检查数据结构中“ key”的值是否可用。如果值不可用,则只有您可以从数据结构中调用api else简单获取,并将其设置为Label。
if let value = dataStructre["key"]{
cell.priceLabel?.text = value
}
else{
callApi()
}
最后,在api调用的成功方法中,使用“密钥标识符”将您从服务器获得的值存储在数据结构中。保存到数据结构后,只需调用“ reloadData”即可。
function callApi(){
if(success){
dataStructure["key"] = value from server
table.reloadData()
}
}