0

I am trying to decode the following JSON response:

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

Into a structure in Swift that looks like this:

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?
}

The line of code I am using to decode is as follows:

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

And it keeps throwing a fatal error but I have no idea why. I have used this method for decoding before with no trouble.

2
  • Learn how to handle errors. Instead of forcing try! Use do try catch and print your decoding error Commented Jun 23, 2018 at 17:41
  • I agree with Leo. Also, please post the full error message. Error messages are meaningful, and help to find what's wrong (most of the time). If you don't understand it, we can help you, but with only code, sometimes we can't guess what's wrong because we might be not sure that the code posted is really the culprit. Commented Jun 23, 2018 at 17:49

3 Answers 3

1

First, to know what's the reason of the error you should do a do-catch block instead of try!:

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

Therefore, you would notice that the error is:

typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "initialprice", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))

which seems to be clear enough; Your json contains strings as values instead of doubles (the floating point values are surrounded by ""). What you should do is to declare TOTicker properties as:

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?
}

Now, you'd notice that you are able to successfully parse it:

let decoder = JSONDecoder()

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

You should see in the log:

TOTicker(success: Optional(true), initialprice: Optional("0.00003592"), price: Optional("0.00006587"), high: Optional("0.00006599"), low: Optional("0.00003499"), volume: Optional("0.68979910"), bid: Optional("0.00006205"), ask: Optional("0.00006595"))

Sign up to request clarification or add additional context in comments.

Comments

1

The problem here as already posted by @AhmadF is that the decoder is expecting to decode Double but found a string instead. A better solution would be to instead of changing the properties type is to implement your own decoder to decode those strings and coerce them to Double.

Note: You should declare your structure properties as constants and only declare optional those that might not be returned by the server (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
}

The custom decoder:

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
    }
}

Now you can properly decode your 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)
}

This will print:

TOTicker(success: true, initialprice: 3.5920000000000002e-05, price: 6.5870000000000005e-05, high: 6.5989999999999997e-05, low: 3.4990000000000002e-05, volume: 0.6897991, bid: 6.2050000000000004e-05, ask: 6.5950000000000004e-05)

Comments

1

All values are strings( marked by "" not the content ) except 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?
}

//

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

1 Comment

try? will never catch any error it will just return an optional and fail silently

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.