【问题标题】:Dynamically change API data fetching structure动态更改 API 数据获取结构
【发布时间】:2018-01-18 10:50:00
【问题描述】:

我正在从一个 API 获取数据,该 API 每天多次将其格式从 String 不规律地更改为 Double..

是否可以对struct 做一些事情以防止在获取时返回 nil 并自动使用正确的类型?

    struct BitcoinGBP : Decodable {
    let price : Double
    let percentChange24h : Double

    private enum CodingKeys : String, CodingKey {
        case price = "PRICE"
        case percentChange24h = "CHANGEPCT24HOUR"
    }
}

简单地使用Double? 会起作用吗?

【问题讨论】:

  • 可解码协议需要知道确切的数据类型才能工作。您应该提前知道数据类型,或者如果您知道一天中数据类型何时更改,您可以将此结构设为泛型并通过在一天中的特定时间设置 String 或 Double 来显式使用。
  • 问题是我不知道 API 什么时候会从 Double 切换到 String 或相反。我不想让我的用户更新每天应用

标签: ios swift api struct


【解决方案1】:

编写一个自定义初始化器来处理这两种情况

struct BitcoinGBP : Decodable {
    let price : Double
    let percentChange24h : Double

    private enum CodingKeys : String, CodingKey {
        case price = "PRICE"
        case percentChange24h = "CHANGEPCT24HOUR"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        percentChange24h = try container.decode(Double.self, forKey: .percentChange24h)
        do {
            price = try container.decode(Double.self, forKey: .price)
        } catch DecodingError.typeMismatch(_, _) {
            let stringValue = try container.decode(String.self, forKey: .price)
            price = Double(stringValue)!
        }
    }
}

【讨论】:

  • 像魅力一样工作!
【解决方案2】:

根据我的经验,您需要设计结构、模型以符合您希望在应用程序中使用的内容,而不是 API 将为您提供的内容。您需要为 API 提供不正确的数据类型或丢失的奇怪数据做好准备。

如果 API 更改太多,那么用户将需要更新,但通常永远不会这样做。端点必须有版本,当有很大差异时需要更改版本。如果不是这种情况,它是有缺陷的 API(这些事情仍然会发生),在这种情况下,您应该使用自己的服务器,代理连接到所需的服务器并将其 API 修改为您自己的。您对其进行了一些测试,以检测他们的 API 是否已更改并尽快修改您自己的 API,以便所有应用程序仍然可以连接到它。但这超出了这个问题的范围。

如果您的结构必须在 24 小时内具有价格和百分比变化,并且两者都是双倍的,那么只需从 API 中期待字符串或任何内容。我喜欢避免使用任何自动执行此操作的工具,因此我只使用便利的构造函数和我自己的一组工具来生成类似的东西:

class BitcoinGBP {

    var price: Double = 0.0
    var priceChange24h: Double = 0.0

    convenience init(price: Double, priceChange24h: Double) {
        self.init()
        self.price = price
        self.priceChange24h = priceChange24h
    }

    /// Construuctor designed to accept JSON formated dictionary
    ///
    /// - Parameter descriptor: A JSON descriptor
    convenience init(descriptor: [String: Any]) {
        self.init()
        self.price = double(value: descriptor["PRICE"]) ?? 0.0
        self.priceChange24h = double(value: descriptor["CHANGEPCT24HOUR"]) ?? 0.0
    }

    /// A conveninece method to extract a double value
    ///
    /// - Parameter value: A value to be converted
    /// - Returns: Double value if possible
    func double(value: Any?) -> Double? {
        if let value = value as? String {
            return Double(value)
        } else if let value = value as? Double {
            return value
        } else if let value = value as? Float {
            return Double(value)
        } else if let value = value as? Int {
            return Double(value)
        } else if let value = value as? Bool {
            return value ? 1.0 : 0.0
        } else {
            return nil
        }
    }
}

现在剩下的就看你需要什么功能了。

【讨论】:

  • 非常感谢 Matic 的精彩解释!我会试试你的方法
猜你喜欢
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
相关资源
最近更新 更多