JSON无法解码为结构(致命错误,Swift)

时间:2018-06-23 17:37:15

标签: json swift struct

我正在尝试解码以下JSON响应:

{"success":true,"initialprice":"0.00003592","price":"0.00006587",
"high":"0.00006599","low":"0.00003499","volume":"0.68979910",
"bid":"0.00006205","ask":"0.00006595"}

在Swift中放入如下结构:

struct TOTicker : Codable {
public var success : Bool?
public var initialprice : Double?
public var price : Double?
public var high : Double?
public var low : Double?
public var volume :Double?
public var bid :Double?
public var ask :Double?
}

我用来解码的代码行如下:

let decoder = JSONDecoder()
let ticker = try! decoder.decode(TOTicker.self, from: jsonData)

它一直抛出致命错误,但我不知道为什么。我以前使用此方法进行解码没有任何麻烦。

3 个答案:

答案 0 :(得分:1)

所有值都是字符串(用""标记而不是内容),除了成功是Bool

struct TOTicker : Codable {
    public var success : Bool?
    public var initialprice : String?
    public var price : String?
    public var high : String?
    public var low : String?
    public var volume :String?
    public var bid :String?
    public var ask :String?
}

//

do {
    let decoder = JSONDecoder()
    let ticker = try decoder.decode(TOTicker.self, from: jsonData)
  }
catch {
      print(error)
}

答案 1 :(得分:1)

首先,要了解错误的原因,您应该执行do-catch块而不是try!

do {
    let ticker = try decoder.decode(TOTicker.self, from: jsonData)
} catch {
    print(error)
}

因此,您会注意到该错误是:

  

typeMismatch(Swift.Double,Swift.DecodingError.Context(codingPath:   [CodingKeys(stringValue:“ initialprice”,intValue:nil)],   debugDescription:“预期对Double进行解码,但找到了字符串/数据   相反。”,underlyingError:nil))

这似乎很清楚;您的json包含 strings 作为值而不是双精度值(浮点值由“”包围)。您应该做的是将TOTicker属性声明为:

struct TOTicker : Codable {
    public var success : Bool?
    public var initialprice : String?
    public var price : String?
    public var high : String?
    public var low : String?
    public var volume :String?
    public var bid :String?
    public var ask :String?
}

现在,您会注意到您能够成功解析它:

let decoder = JSONDecoder()

do {
    let ticker = try decoder.decode(TOTicker.self, from: jsonData)
    print(ticker)
} catch {
    print(error)
}

您应该在日志中看到:

  

TOTicker(成功:可选(true),初始价格:   可选(“ 0.00003592”),价格:可选(“ 0.00006587”),最高:   可选(“ 0.00006599”),低:可选(“ 0.00003499”),音量:   可选(“ 0.68979910”),出价:可选(“ 0.00006205”),询问:   可选(“ 0.00006595”))

答案 2 :(得分:1)

@AhmadF已经在这里发布的问题是,解码器希望对Double进行解码,但却找到了一个字符串。更好的解决方案是,不要更改属性类型,而是实现自己的解码器来解码那些字符串并将其强制为Double。

注意:您应该将结构属性声明为常量,并且仅声明服务器(api)可能不返回的可选属性:

struct TOTicker: Codable {
    let success: Bool
    let initialprice: Double
    let price: Double
    let high: Double
    let low: Double
    let volume: Double
    let bid: Double
    let ask: Double
}

自定义解码器:

extension TOTicker {
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        guard
            let initialprice = try Double(container.decode(String.self, forKey: .initialprice)),
            let price = try Double(container.decode(String.self, forKey: .price)),
            let high = try Double(container.decode(String.self, forKey: .high)),
            let low = try Double(container.decode(String.self, forKey: .low)),
            let volume = try Double(container.decode(String.self, forKey: .volume)),
            let bid = try Double(container.decode(String.self, forKey: .bid)),
            let ask = try Double(container.decode(String.self, forKey: .ask))
        else {
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Error decoding String into Double"))
        }
        success = try container.decode(Bool.self, forKey: .success)
        self.initialprice = initialprice
        self.price = price
        self.high = high
        self.low = low
        self.volume = volume
        self.bid = bid
        self.ask = ask
    }
}

现在您可以正确解码json了:

let data = Data("""
{"success":true,"initialprice":"0.00003592","price":"0.00006587",
    "high":"0.00006599","low":"0.00003499","volume":"0.68979910",
    "bid":"0.00006205","ask":"0.00006595"}
""".utf8)

let decoder = JSONDecoder()
do {
    let ticker = try decoder.decode(TOTicker.self, from: data)
    print(ticker)
} catch {
    print(error)
}

这将打印:

  

TOTicker(成功:true,初始价格:3.5920000000000002e-05,价格:   6.5870000000000005e-05,高:6.5989999999999997e-05,低:3.4990000000000002e-05,数量:0.6897991,出价:6.2050000000000004e-05,要求:6.5950000000000004e-05)