I am writing an application to track the cryptocurrency exchange rate. The api has separate url requests for each coin. Here is a JSON response coming from the server, to a request for one coin:
{
"status": {
"elapsed": 2,
"timestamp": "2022-08-23T06:10:16.417580964Z"
},
"data": {
"id": "1e31218a-e44e-4285-820c-8282ee222035",
"serial_id": 6057,
"symbol": "BTC",
"name": "Bitcoin",
"slug": "bitcoin",
"contract_addresses": null,
"_internal_temp_agora_id": "9793eae6-f374-46b4-8764-c2d224429791",
"market_data": {
"price_usd": 20946.467798282705,
"price_btc": 1,
"price_eth": 13.351682485155417,
"volume_last_24_hours": 7635594314.553516,
"real_volume_last_24_hours": 6038552423.10257,
"volume_last_24_hours_overstatement_multiple": 1.2644742944254175,
"percent_change_usd_last_1_hour": null,
"percent_change_btc_last_1_hour": null,
"percent_change_eth_last_1_hour": null,
"percent_change_usd_last_24_hours": -2.1478472228280485,
"percent_change_btc_last_24_hours": 0.11113305637977958,
"percent_change_eth_last_24_hours": 0.0518833986287626,
"ohlcv_last_1_hour": null,
"ohlcv_last_24_hour": null,
"last_trade_at": "2022-08-23T06:10:15Z"
}
I need to send several url requests and convert the received responses into a table where each cell is a certain coin corresponding to a certain url request.
I wrote a model and a service layer, but when sending two requests, instead of two cells in the table, I get one cell that displays data from the 1st request, and then abruptly changes to data from the second request.
The code is given below:
Сontroller
final class WalletController: UIViewController {
private let walletTable = UITableView()
private let service = WalletService()
private var data: [DataWallet] = []
private let identifier = "walletCell"
private var pointSorted = 1
private let queue = DispatchQueue.main
// MARK: Life cycle
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
configData()
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
self.navigationItem.setHidesBackButton(true, animated: true)
}
// MARK: setUpView
private func setUpView() {
// NavigationBar
createCustomNavigationBar()
// LogOutBarButton
let logOutButton = createCustomButton(titleName: "LogOut", selector: #selector(logOutButtonTapped))
navigationItem.leftBarButtonItem = logOutButton
// SortedBarButton
let sortedButton = createCustomButton(titleName: "Sorted", selector: #selector(sortedButtonTapped))
navigationItem.rightBarButtonItem = sortedButton
// TableView
walletTable.backgroundColor = #colorLiteral(red: 0.9381344914, green: 0.9331676364, blue: 0.9246369004, alpha: 1)
walletTable.separatorColor = #colorLiteral(red: 0.1599435508, green: 0.185090214, blue: 0.167404592, alpha: 1)
walletTable.delegate = self
walletTable.dataSource = self
walletTable.register(UITableViewCell.self, forCellReuseIdentifier: identifier)
view.addSubview(walletTable)
walletTable.snp.makeConstraints { maker in
maker.left.top.right.bottom.equalToSuperview().inset(0)
}
}
@objc private func logOutButtonTapped() {
let startController = StartController()
navigationController?.pushViewController(startController, animated: true)
}
private func configData() {
service.addCoin { [weak self] result in
switch result {
case .success(let dataBoy):
self?.data = [dataBoy]
DispatchQueue.main.async {
self?.walletTable.reloadData()
}
case.failure(let error):
print(error)
}
}
}
@objc private func sortedButtonTapped() {
if pointSorted == 1 {
data = data.sorted{ $0.capital < $1.capital }
pointSorted = pointSorted - 1
} else {
data = data.sorted{ $0.country < $1.country }
pointSorted = pointSorted + 1
}
walletTable.reloadData()
}
}
// MARK: Delegate
extension WalletController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
// MARK: DataSource
extension WalletController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = walletTable.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.backgroundColor = #colorLiteral(red: 0.9381344914, green: 0.9331676364, blue: 0.9246369004, alpha: 1)
let coin = data[indexPath.row]
var content = cell.defaultContentConfiguration()
content.text = coin.symbol
content.secondaryText = String(coin.market_data.percent_change_usd_last_1_hour ?? 0.0)
cell.contentConfiguration = content
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let coin = data[indexPath.row]
let infoController = InfoController()
queue.async {
infoController.firstTextLabel.text = coin.name
infoController.firstNumberLabel.text = coin.symbol
infoController.secondTextLabel.text = coin.name
infoController.secondNumberLabel.text = String(coin.market_data.price_btc ?? 0.0)
infoController.thirdTextLabel.text = coin.name
infoController.thirdNumberLabel.text = String(coin.market_data.price_usd ?? 0.0)
}
navigationController?.pushViewController(infoController, animated: true)
}
}
Service layer
final class WalletService {
func addCoin(completion: @escaping (Result<DataWallet, Error>) -> Void) {
guard let urlBtc = URL(string: "https://data.messari.io/api/v1/assets/btc/metrics") else { return }
guard let urlEth = URL(string: "https://data.messari.io/api/v1/assets/eth/metrics") else { return }
let taskBtc = URLSession.shared.dataTask(with: urlBtc) { data, _, error in
if let error = error {
completion(.failure(error))
} else if let data = data {
do {
let result = try JSONDecoder().decode(Response.self, from: data)
completion(.success(result.data))
} catch {
completion(.failure(error))
}
}
}
taskBtc.resume()
let taskEth = URLSession.shared.dataTask(with: urlEth) { data, _, error in
if let error = error {
completion(.failure(error))
} else if let data = data {
do {
let result = try JSONDecoder().decode(Response.self, from: data)
completion(.success(result.data))
} catch {
completion(.failure(error))
}
}
}
taskEth.resume()
}
}
Model
struct Response: Codable {
let status: Status
let data: DataWallet
}
struct Status: Codable {
let elapsed: Int?
let timestamp: String?
}
struct DataWallet: Codable {
let id: String?
let symbol: String?
let name: String?
let market_data: MarketData
}
struct MarketData: Codable {
let price_usd: Double?
let price_btc: Double?
let percent_change_usd_last_1_hour: Double?
let percent_change_btc_last_1_hour: Double?
}
Can you tell me what I'm doing wrong and how to fix this situation?
I will be grateful for any help!