API Fetch 返回 nil
Posted
技术标签:
【中文标题】API Fetch 返回 nil【英文标题】:API Fetch returns nil 【发布时间】:2021-12-27 03:29:42 【问题描述】:fetch 没有抛出任何错误,它只是返回 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: $0.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 ""
当我打印我得到的回报时:
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 ...
行下打印数据,因此确认问题出在使用我的模型解码时,我做错了什么?
【问题讨论】:
【参考方案1】:我从未直接使用 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
【讨论】:
我不能像那样对令牌(比特币)进行硬编码,因为它会改变。为了简单起见,我只放了 1,但看看这个请求:https://api.coingecko.com/api/v3/simple/price?ids=tether%2Cwmatic%2Cethereum%2Cmoonriver&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true
你可以看到它可以包含无限量
如果是这样,您可以尝试将它们解码为字典,我在这里添加了一个基于您的 JSON 的工作示例pastecode.io/s/tkim2jf0@Albert
嗨@Albert,请告诉我它是否适用于您的情况,如果没有,我们将尝试另一种方式
我现在正在测试它,它不起作用:/ 我试过这个:let data = try JSONDecoder().decode(Coin.self, from: undecodedData.data(using: .utf8)!)
我得到Cannot infer contextual base in reference to member 'utf8'
和Value of type 'Data' has no member 'data'
另外我如何将所有字符串分配给模型而不做额外的计算?
不,我使用的是 .data(使用:.utf8)!因为我的数据是字符串,在你的情况下你可以直接解码 JSONDecoder().decode(Coin.self, from: undecodedData)【参考方案2】:
您的值在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
【讨论】:
请阅读我为@sushitrash 留下的评论,我无法对比特币进行硬编码,因为有无限数量的硬币,我怎样才能使它更灵活? 除非这些键都被命名为bitcoin
,否则它们无关紧要。
查看simple
端点的文档,无论如何这不是真的。 coingecko.com/en/api/documentation
如果我尝试它会说:keyNotFound(CodingKeys(stringValue: "bitcoin", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"bitcoin\", intValue: nil) (\"bitcoin\").", underlyingError: nil))
以上是关于API Fetch 返回 nil的主要内容,如果未能解决你的问题,请参考以下文章