[英]Create object using multiple independent API calls
I am working on a practice project with the CoinGecko API.我正在使用 CoinGecko API 进行练习项目。 I just figured out how to successfully fetch, parse, and display data from the API, but I have ran into an issue.我刚刚弄清楚如何从 API 成功获取、解析和显示数据,但我遇到了一个问题。 Currently I am only fetching a single coin, using a single URL but I would like to be able to fetch multiple (3 in this case), all at once and display them.目前我只使用单个 URL 获取单个硬币,但我希望能够一次获取多个(在本例中为 3 个)并显示它们。 Not sure how to proceed, or if my explanation makes sense so I have attached my code below.不知道如何继续,或者我的解释是否有意义,所以我在下面附上了我的代码。 Thanks in advance.提前致谢。
CoinListViewModel CoinListViewModel
import Foundation
class CoinListViewModel {
private(set) var coin: Coin
init(coin: Coin) {
self.coin = coin
}
func getCoins(url: URL) async {
do {
let coin = try await WebService().getCoins(url: url)
self.coin = coin
} catch {
print(error)
}
}
}
struct CoinViewModel {
private let coin: Coin
init(coin: Coin) {
self.coin = coin
}
var symbol: String {
coin.symbol
}
var name: String {
coin.name
}
var price: [String: Double] {
coin.marketData.currentPrice
}
}
WebService网络服务
import Foundation
enum CoinsError: Error {
case invalidServerResponse
}
class WebService {
func getCoins(url: URL) async throws -> Coin {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw CoinsError.invalidServerResponse
}
return try JSONDecoder().decode(Coin.self, from: data)
}
}
Constants常数
import Foundation
struct Constants {
struct coinURLs {
static let allCoinURLs = [
URL(string: "https://api.coingecko.com/api/v3/coins/bitcoin")!,
URL(string: "https://api.coingecko.com/api/v3/coins/ethereum")!,
URL(string: "https://api.coingecko.com/api/v3/coins/litecoin")!
]
}
}
Coin硬币
import Foundation
// MARK: - WelcomeElement
struct Coin: Codable {
let symbol, name: String
let marketData: MarketData
enum CodingKeys: String, CodingKey {
case symbol, name
case marketData = "market_data"
}
static var DefaultCoin = Coin(symbol: " ", name: " ", marketData: MarketData(currentPrice: ["usd": 0.0]))
}
struct Tion: Codable {
let en: String
enum CodingKeys: String, CodingKey {
case en
}
}
struct MarketData: Codable {
let currentPrice: [String: Double]
enum CodingKeys: String, CodingKey {
case currentPrice = "current_price"
}
}
CoinListViewController CoinListViewController
import Foundation
import UIKit
class CoinListViewController: UITableViewController {
private let vm = CoinListViewModel(coin: Coin.DefaultCoin)
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
Task {
await getCoins()
}
}
private func configureUI() {
self.navigationController?.navigationBar.prefersLargeTitles = true
self.title = "CoinFlip"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "StockCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "StockCell", for: indexPath)
let coin = vm.coin
var content = cell.defaultContentConfiguration()
content.text = coin.name
content.secondaryText = "$\(Int(coin.marketData.currentPrice["usd"] ?? 0))"
cell.contentConfiguration = content
return cell
}
private func getCoins() async {
await vm.getCoins(url: Constants.coinURLs.allCoinURLs[0])
print(vm.coin)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
You can spawn multiple network calls if you make a few changes to your WebService
.如果您对WebService
进行一些更改,则可以产生多个网络调用。 This will also return a partial result if fetching a coin fails.如果获取硬币失败,这也将返回部分结果。
func getCoins(urls: [URL]) async throws -> [Coin] {
return try await withThrowingTaskGroup(of: Coin.self, body: { taskGroup in
var coins = [Coin]()
urls.forEach { url in
taskGroup.addTask {
let (data, response) = try await URLSession.shared.data(from: url)
guard
let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200
else { return Coin() }
return try JSONDecoder().decode(Coin.self, from: data)
}
}
for try await coin in taskGroup {
coins.append(coin)
}
return coins
})
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.