API 获取 returns 无
API Fetch returns nil
获取没有抛出任何错误,它只是 returns nil,我不知道为什么,这是 api URL:
https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true
注意:代币的数量是无限的,不仅仅是比特币,所以我不能硬编码。
看起来像:
{
"bitcoin": {
"usd": 51110,
"usd_market_cap": 964544028181.903,
"usd_24h_vol": 19080677597.123028,
"usd_24h_change": 2.163373654971005,
"last_updated_at": 1640575480
},
thereCanBeMoreWhichIcan'tPredict: {
...
}
}
这是我创建的模型:
struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable {
let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
let last_updated_at: Int?
}
这就是我使用 Alamofire 获取它的方式:
func afRequest(url: URL) async throws -> Data {
try await withUnsafeThrowingContinuation { continuation in
// If another error try lowering the request error: (statusCode: 200..<300)
// timeoutInterval is in seconds
AF.request(url, method: .get, requestModifier: { [=15=].timeoutInterval = .infinity }).validate(statusCode: 200..<600).responseData { response in
if let data = response.data {
continuation.resume(returning: data)
return
}
if case let .failure(error) = response.result {
print(" Error on afRequest(): \(error)")
continuation.resume(throwing: error)
return
}
}
}
}
func getDataFromAPI(url: String) async -> Any {
do {
let url = URL(string: url)!
let undecodedData = try await afRequest(url: url)
let finalData = try JSONDecoder().decode(TokenSimplePriceCoingeckoUsdModel.self, from: undecodedData)
return finalData
} catch(let error) {
print(" Error on getDataFromAPI(): ", error)
}
return ""
}
当我打印 return 时,我得到:
TokenSimplePriceCoingeckoUsdModel(usd: nil, usd_market_cap: nil, usd_24h_vol: nil, usd_24h_change: nil, last_updated_at: nil)
编辑:如果我这样做:
print(String(data: undecodedData, encoding: .utf8)!)
在 let undecodedData ...
行下它打印数据,所以确认问题是在用我的模型解码它时,我做错了什么?
我从来没有直接使用 alamofire 发出网络请求,但似乎错误在于你如何解码响应,假设 undecodedData
已经包含你想要的数据,你当前的响应模型不解码“比特币”密钥,因此结构为零,您可以将结构更改为
struct BitcoinStats: Codable, Hashable {
let bitcoin: TokenSimplePriceCoingeckoUsdModel
}
struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable {
let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
let last_updated_at: Int?
}
或者您可能想尝试直接解码“比特币”密钥的值,这样您就可以保持当前结构不变
更新:
因为 JSON 除了“比特币”之外还有其他密钥,这是我提出的动态解码数据的解决方案,无需对密钥进行硬编码:
pastecode.io/s/tkim2jf0
您的值在 bitcoin
对象中,因此您也需要对其进行解码。您可以从 quicktype.io:
这个结构开始
struct Prices: Decodable {
let bitcoin: Bitcoin
}
// MARK: - Bitcoin
struct Bitcoin: Decodable {
let usd: Int
let usdMarketCap, usd24HVol, usd24HChange: Double
let lastUpdatedAt: Int
enum CodingKeys: String, CodingKey {
case usd
case usdMarketCap = "usd_market_cap"
case usd24HVol = "usd_24h_vol"
case usd24HChange = "usd_24h_change"
case lastUpdatedAt = "last_updated_at"
}
}
然后就可以使用Alamofire 5.5新的async
方法自动解码了:
let response = await AF.request(url).serializingDecodable(Prices.self).response
获取没有抛出任何错误,它只是 returns nil,我不知道为什么,这是 api URL:
https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true
注意:代币的数量是无限的,不仅仅是比特币,所以我不能硬编码。
看起来像:
{
"bitcoin": {
"usd": 51110,
"usd_market_cap": 964544028181.903,
"usd_24h_vol": 19080677597.123028,
"usd_24h_change": 2.163373654971005,
"last_updated_at": 1640575480
},
thereCanBeMoreWhichIcan'tPredict: {
...
}
}
这是我创建的模型:
struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable {
let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
let last_updated_at: Int?
}
这就是我使用 Alamofire 获取它的方式:
func afRequest(url: URL) async throws -> Data {
try await withUnsafeThrowingContinuation { continuation in
// If another error try lowering the request error: (statusCode: 200..<300)
// timeoutInterval is in seconds
AF.request(url, method: .get, requestModifier: { [=15=].timeoutInterval = .infinity }).validate(statusCode: 200..<600).responseData { response in
if let data = response.data {
continuation.resume(returning: data)
return
}
if case let .failure(error) = response.result {
print(" Error on afRequest(): \(error)")
continuation.resume(throwing: error)
return
}
}
}
}
func getDataFromAPI(url: String) async -> Any {
do {
let url = URL(string: url)!
let undecodedData = try await afRequest(url: url)
let finalData = try JSONDecoder().decode(TokenSimplePriceCoingeckoUsdModel.self, from: undecodedData)
return finalData
} catch(let error) {
print(" Error on getDataFromAPI(): ", error)
}
return ""
}
当我打印 return 时,我得到:
TokenSimplePriceCoingeckoUsdModel(usd: nil, usd_market_cap: nil, usd_24h_vol: nil, usd_24h_change: nil, last_updated_at: nil)
编辑:如果我这样做:
print(String(data: undecodedData, encoding: .utf8)!)
在 let undecodedData ...
行下它打印数据,所以确认问题是在用我的模型解码它时,我做错了什么?
我从来没有直接使用 alamofire 发出网络请求,但似乎错误在于你如何解码响应,假设 undecodedData
已经包含你想要的数据,你当前的响应模型不解码“比特币”密钥,因此结构为零,您可以将结构更改为
struct BitcoinStats: Codable, Hashable {
let bitcoin: TokenSimplePriceCoingeckoUsdModel
}
struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable {
let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
let last_updated_at: Int?
}
或者您可能想尝试直接解码“比特币”密钥的值,这样您就可以保持当前结构不变
更新: 因为 JSON 除了“比特币”之外还有其他密钥,这是我提出的动态解码数据的解决方案,无需对密钥进行硬编码: pastecode.io/s/tkim2jf0
您的值在 bitcoin
对象中,因此您也需要对其进行解码。您可以从 quicktype.io:
struct Prices: Decodable {
let bitcoin: Bitcoin
}
// MARK: - Bitcoin
struct Bitcoin: Decodable {
let usd: Int
let usdMarketCap, usd24HVol, usd24HChange: Double
let lastUpdatedAt: Int
enum CodingKeys: String, CodingKey {
case usd
case usdMarketCap = "usd_market_cap"
case usd24HVol = "usd_24h_vol"
case usd24HChange = "usd_24h_change"
case lastUpdatedAt = "last_updated_at"
}
}
然后就可以使用Alamofire 5.5新的async
方法自动解码了:
let response = await AF.request(url).serializingDecodable(Prices.self).response