【问题标题】:Swift - How to extract all values with same key namesSwift - 如何提取具有相同键名的所有值
【发布时间】:2021-05-23 12:41:11
【问题描述】:

看了几篇帖子,我没有找到我要找的东西。我希望这篇文章对我有帮助。

我使用 CoinDesk 的 api,我现在要做的是在答案中检索所有代码(欧元、美元、英镑),但我无法获得所有资产。

    {
  "time": {
    "updated": "Feb 20, 2021 19:48:00 UTC",
    "updatedISO": "2021-02-20T19:48:00+00:00",
    "updateduk": "Feb 20, 2021 at 19:48 GMT"
  },
  "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org",
  "chartName": "Bitcoin",
  "bpi": {
    "USD": {
      "code": "USD",
      "symbol": "$",
      "rate": "57,014.5954",
      "description": "United States Dollar",
      "rate_float": 57014.5954
    },
    "GBP": {
      "code": "GBP",
      "symbol": "£",
      "rate": "40,681.1111",
      "description": "British Pound Sterling",
      "rate_float": 40681.1111
    },
    "EUR": {
      "code": "EUR",
      "symbol": "€",
      "rate": "47,048.5582",
      "description": "Euro",
      "rate_float": 47048.5582
    }
  }
}

这就是我将如何获取数据

公共类 NetworkManager {

static public func fetchBPI() {
    let url = "https://api.coindesk.com/v1/bpi/currentprice.json"
    Alamofire.request(url).responseJSON { response in
        switch response.result {
        case .success:
            print("✅ Success ✅")
            if let json = response.data {
                do {
                    let data = try JSON(data: json)
                    print(data)
                    
                    let context = PersistentContainer.context
                    let entity = NSEntityDescription.entity(forEntityName: "BPI", in: context)
                    let newObject = NSManagedObject(entity: entity!, insertInto: context)
                    
                    //Date Formatter
                    let dateFormatter = DateFormatter()
                    dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
                    let date = dateFormatter.date(from: data["time"]["updated"].rawValue as! String)
                    dateFormatter.timeZone = NSTimeZone.local
                    let timeStamp = dateFormatter.string(from: date ?? Date())
                    
                    newObject.setValue(timeStamp, forKey: "time")
                    newObject.setValue(data["chartName"].rawValue, forKey: "chartName")
                    newObject.setValue(data["bpi"]["EUR"]["symbol"].rawValue, forKey: "symbol")
                    newObject.setValue(data["bpi"]["EUR"]["rate"].rawValue, forKey: "rate")
                    newObject.setValue(data["bpi"]["EUR"]["code"].rawValue, forKey: "code")
                    
                    do {
                        try context.save()
                        print("✅ Data saved ✅")
                    } catch let error {
                        print(error)
                        print("❌ Saving Failed ❌")
                    }
                }
                catch {
                    print("❌ Error ❌")
                }
            }
        case .failure(let error):
            print(error)
        }
    }
}

}

我想把所有的代码都放入bpi key,放到一个列表中使用。

【问题讨论】:

  • 不清楚您的代码有什么问题,您能否在问题中添加更清晰的实际问题描述?
  • 我想获得一些 api (EUR,USD,GBP) 并将它们放在一个列表中以便以后使用它们,目前,在我的请求中我只获得了 EUR。

标签: json swift alamofire decodable


【解决方案1】:

我认为这里处理 json 的最佳方法是将“bpi”下的内容视为字典。

struct CoinData: Codable {
    let time: Time
    let chartName: String
    let bpi: [String: BPI]
}

struct BPI: Codable {
    let code: String
    let rate: Double

    enum CodingKeys: String, CodingKey {
        case code
        case rate = "rate_float"
    }
}

struct Time: Codable {
    let updated: Date

    enum CodingKeys: String, CodingKey {
        case updated = "updatedISO"
    }
}

我删除了一些不必要的 (?) 属性,还注意到我将 Time 中的 updatedISO 变成了 Date,如果这可能有用的话,因为它很容易转换。

要正确解码,请使用 trydo/catch,以便正确处理错误。

这是一个示例,其中我还循环了不同的货币/汇率

do {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601
    let result = try decoder.decode(CoinData.self, from: data)

    print(result.time.updated)
    let coins = result.bpi.values
    for coin in coins {
        print(coin)
    }
} catch {
    print(error)
}

输出:

2021-02-20 19:48:00 +0000
BPI(代码:“GBP”,汇率:40681.1111)
BPI(代码:“USD”,汇率:57014.5954)
BPI(代码:“EUR”,汇率:47048.5582)

【讨论】:

  • 将其添加到列表中是什么意思?
  • 但是在我上面的示例中,coins 中有这个。我不确定你说的是什么代码和费率。
  • 如果我理解正确,您正在尝试将字典的值分配给属性。试试bpi = result.bpi
【解决方案2】:

您应该使用对象来表示来自服务器的数据。应该是这样的:

struct CoinData: Codable {
    let time: Time
    let disclaimer, chartName: String
    let bpi: BPI
}

struct BPI: Codable {
    let usd, gbp, eur: Eur

    enum CodingKeys: String, CodingKey {
        case usd = "USD"
        case gbp = "GBP"
        case eur = "EUR"
    }
}

struct Eur: Codable {
    let code, symbol, rate, eurDescription: String
    let rateFloat: Double

    enum CodingKeys: String, CodingKey {
        case code, symbol, rate
        case eurDescription = "description"
        case rateFloat = "rate_float"
    }
}

struct Time: Codable {
    let updated: String
    let updatedISO: String
    let updateduk: String
}

当你下载数据时,你会像这样解析它:

let coinData = try? JSONDecoder().decode(CoinData.self, from: jsonData)
coinData?.bpi.eur  // Access EUR for instance

更新

使用从服务器获取的数据演示解析的简单演示:

let dataFromServer = "{\"time\":{\"updated\":\"Feb 20, 2021 21:02:00 UTC\",\"updatedISO\":\"2021-02-20T21:02:00+00:00\",\"updateduk\":\"Feb 20, 2021 at 21:02 GMT\"},\"disclaimer\":\"This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org\",\"chartName\":\"Bitcoin\",\"bpi\":{\"USD\":{\"code\":\"USD\",\"symbol\":\"$\",\"rate\":\"56,689.8367\",\"description\":\"United States Dollar\",\"rate_float\":56689.8367},\"GBP\":{\"code\":\"GBP\",\"symbol\":\"£\",\"rate\":\"40,449.3889\",\"description\":\"British Pound Sterling\",\"rate_float\":40449.3889},\"EUR\":{\"code\":\"EUR\",\"symbol\":\"€\",\"rate\":\"46,780.5666\",\"description\":\"Euro\",\"rate_float\":46780.5666}}}"

do {
    let json = try JSONDecoder().decode(CoinData.self, from: dataFromServer.data(using: .utf8)!)
    print(json.bpi.eur)  // Will print EUR object
} catch let error {
    print(error)
}

【讨论】:

  • @jocewl 如果让 json = response.data { } 这就是您所需要的,您可以在其中解析来自服务器的数据。所以你把“json”放在那里。 try? JSONDecoder().decode(CoinData.self, from: json)
  • 是的,没错。但是您在问题中发布的 JSON 是正确的吗?它是你做print(data)时打印的那个?
  • @jocewl 我将 updatedISO 值从 Date 更改为 String,并在操场上对其进行了测试,它应该可以工作
  • @jocewl 正如我所写,我更新了我的答案,您也应该更新您的代码。只需再次复制粘贴整个代码即可。
  • 你应该放在那里json
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-01
  • 1970-01-01
  • 2020-06-19
  • 2014-11-03
相关资源
最近更新 更多