是否可以通过相同的结构从不同但相似的API(不同的URL但类似的JSON构造)获取数据?
例如,使用bitcoinUSD.raw.eth.usd.price
和bitcoinUSD.raw.eth.gbp.price
访问数据:
struct Bitcoin : Decodable {
private enum CodingKeys : String, CodingKey { case raw = "RAW" }
let raw : BitcoinRAW
}
struct BitcoinRAW : Decodable {
private enum CodingKeys : String, CodingKey { case btc = "BTC" }
let btc : BitcoinETH
}
struct BitcoinETH : Decodable {
private enum CodingKeys : String, CodingKey {
case usd = "USD"
case gbp = "GBP"
}
let usd : BitcoinUSD
let gbp : BitcoinGBP
}
struct BitcoinUSD : Decodable {
let price : Double
let percentChange24h : Double
private enum CodingKeys : String, CodingKey {
case price = "PRICE"
case percentChange24h = "CHANGEPCT24HOUR"
}
}
struct BitcoinGBP : Decodable {
let price : Double
let percentChange24h : Double
private enum CodingKeys : String, CodingKey {
case price = "PRICE"
case percentChange24h = "CHANGEPCT24HOUR"
}
}
以下是我的数据提取功能:
enum MyErrorBTC : Error {
case FoundNil(String)
}
class BitcoinInfo : NSObject {
static var btcURL : URL?
func fetchBitcoinInfo(completion: @escaping (Bitcoin?, Error?) -> Void) {
if WalletViewController.currencyUSD == true {
BitcoinInfo.btcURL = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC&tsyms=USD")!
let task = URLSession.shared.dataTask(with: BitcoinInfo.btcURL!) { (data, response, error) in
guard let data = data else { return }
do {
if let bitcoinPrice = try? JSONDecoder().decode(Bitcoin.self, from: data) {
completion(bitcoinPrice, nil)
//print("price =", bitcoinUSD.raw.btc.usd.price)
throw MyErrorBTC.FoundNil("bitcoinPrice")
}
} catch {
print(error)
}
}
task.resume()
} else if WalletViewController.currencyGBP == true {
BitcoinInfo.btcURL = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC&tsyms=GBP")!
let task = URLSession.shared.dataTask(with: BitcoinInfo.btcURL!) { (data, response, error) in
guard let data = data else { return }
do {
if let bitcoinPrice = try? JSONDecoder().decode(Bitcoin.self, from: data) {
completion(bitcoinPrice, nil)
//print("price =", bitcoinUSD.raw.btc.gbp.price)
throw MyErrorBTC.FoundNil("bitcoinPrice")
}
} catch {
print(error)
}
}
task.resume()
}
}
}
请注意,当调用任一函数时,此代码返回nil。 有没有办法修改它?
答案 0 :(得分:0)
如果您的目标只是让您的获取功能更具可重用性,那么两个端点之间的唯一区别就是货币。在这种情况下,为什么不直接将货币作为参数传递,并使用您获得的货币参数构建您的URL。这看起来像这样:
func fetchBitcoinInfo(forCurrency currency: String, _ completion: @escaping (Bitcoin?, Error?) -> Void) {
BitcoinInfo.btcURL = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC&tsyms=\(currency)")!
let task = URLSession.shared.dataTask(with: BitcoinInfo.ethURL!) { (data, response, error) in
guard let data = data else { return }
do {
if let bitcoinPrice = try? JSONDecoder().decode(Bitcoin.self, from: data) {
completion(bitcoinPrice, nil)
} else {
throw MyErrorBTC.FoundNil("bitcoinPrice")
}
} catch {
print(error)
}
}
task.resume()
}
顺便说一下,当你 获得有效的FoundNil
对象时,你正在抛出Bitcoin
,这没有任何意义。我将您的错误抛出到else
语句中,这样只有在bitcoinPrice
展开失败时它才会抛出。
答案 1 :(得分:0)
是的,但您应该将变量声明为可选:
struct BitcoinETH : Decodable {
private enum CodingKeys : String, CodingKey {
case usd = "USD"
case gbp = "GBP"
}
let usd : BitcoinUSD?
let gbp : BitcoinGBP?
}
如果没有,将抛出异常并且您将获得整个结构的零值,因为它不会被解码为解码器预期的