Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JSON未解码为结构(致命错误,Swift)_Json_Swift_Struct - Fatal编程技术网

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

JSON未解码为结构(致命错误,Swift),json,swift,struct,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

我正在尝试解码以下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)
它不断抛出致命错误,但我不知道为什么。我以前使用过这种方法进行解码,没有遇到任何问题。

所有值都是字符串(由
标记,而不是内容),除了success is
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?
}
//

除success为
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 catch
块,而不是
try

do {
    let ticker = try decoder.decode(TOTicker.self, from: jsonData)
} catch {
    print(error)
}
因此,您会注意到错误是:

类型不匹配(Swift.Double、Swift.DecodingError.Context)(编码路径: [CodingKeys(stringValue:“initialprice”,intValue:nil)], debugDescription:“应解码双精度,但找到字符串/数据 而不是。”,underyingerror:nil))

这似乎很清楚;json将字符串作为值而不是双精度值(浮点值被“”包围)。您应该做的是将
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(成功:可选(正确),初始价格: 可选(“0.00003592”),价格:可选(“0.00006587”),高: 可选(“0.00006599”),低:可选(“0.00003499”),音量: 可选(“0.68979910”),投标:可选(“0.00006205”),要求: 可选(“0.00006595”))


首先,要知道错误的原因,您应该执行
do catch
块,而不是
try

do {
    let ticker = try decoder.decode(TOTicker.self, from: jsonData)
} catch {
    print(error)
}
因此,您会注意到错误是:

类型不匹配(Swift.Double、Swift.DecodingError.Context)(编码路径: [CodingKeys(stringValue:“initialprice”,intValue:nil)], debugDescription:“应解码双精度,但找到字符串/数据 而不是。”,underyingerror:nil))

这似乎很清楚;json将字符串作为值而不是双精度值(浮点值被“”包围)。您应该做的是将
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(成功:可选(正确),初始价格: 可选(“0.00003592”),价格:可选(“0.00006587”),高: 可选(“0.00006599”),低:可选(“0.00003499”),音量: 可选(“0.68979910”),投标:可选(“0.00006205”),要求: 可选(“0.00006595”))


@AhmadF已经发布的问题是,解码器希望解码双精度,但却找到了一个字符串。更好的解决方案是实现自己的解码器来解码这些字符串并强制它们加倍,而不是更改属性类型

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


自定义解码器:

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)
}
这将打印:

托蒂克(成功:真,初始价格:3.5920000000002E-05,价格: 6.58700000000005E-05,高:6.5989999999797E-05,低:3.499000000000002E-05,体积:0.6897991,投标:6.205000000000004E-05,询价:6.5950000000000004e-05)


@AhmadF已经发布的问题是,解码器希望解码双精度,但却找到了一个字符串。更好的解决方案是实现自己的解码器来解码这些字符串并强制它们加倍,而不是更改属性类型

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


自定义解码器:

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)
}
这将打印:

托蒂克(成功:真,初始价格:3.5920000000002E-05,价格: 6.58700000000005E-05,高:6.5989999999797E-05,低:3.499000000000002E-05,体积:0.6897991,投标:6.205000000000004E-05,询价:6.5950000000000004e-05)


学习如何处理错误。而不是强迫尝试!使用“尝试捕捉并打印您的解码错误”我同意Leo的观点。另外,请发布完整的错误消息。错误消息是有意义的,并且有助于发现错误(大多数情况下)。如果您不理解,我们可以帮助您,但仅使用代码,有时我们无法猜测错误,因为我们可能不确定发布的代码是否真的是罪魁祸首。了解如何处理错误。而不是强迫尝试!使用“尝试捕捉并打印您的解码错误”我同意Leo的观点。另外,请发布完整的错误消息。错误消息是有意义的,并且有助于发现错误(大多数情况下)。如果您不明白,我们可以帮助您,但只需代码,有时我们猜不出哪里出了问题,因为我们可能不确定发布的代码是否真的是罪魁祸首。
try?
永远不会捕获任何错误它只会返回一个可选的,然后默默地失败
try?
永远不会捕获任何错误它只会返回一个可选的,然后默默地失败