0

I need to parse JSON from an API to get two arrays of data, one for Times, and one for Prices.

Here is the request:

func getReq(arr: Bool, completion: @escaping (Bool) -> ()){
    Dates.shared.formatDate()

    switch graphSetup {
    case .day:
        days = "1"
    case .week:
        days = "14"
    }

    let url = "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=1"

    Alamofire.request(url).responseJSON { response in
        switch response.result {
        case .failure(let error):
            // Do whatever here
            return

        case .success(let data):
            // First make sure you got back a dictionary if that's what you expect
            let responseJSON = JSON(response.result.value!)
            if responseJSON.count != 0 {

                //do whatever you want with your object json

                parse(json: responseJSON)
                print(responseJSON)
                let gd = responseJSON["prices"].arrayValue

                completion(arr)
            }
        }
    }

This is exactly what JSON returns (print(responseJSON) I shortened it.

let json = "{
  "prices" : [
[
  1535841336422,
  7186.4600704446984
],
[
  1535841628453,
  7187.2085293179398
],
[
  1535841936398,
  7189.7057414152769
],
... many others ...,
[
  1535889024161,
  7210.4807839639352
],
[
  1535889339150,
  7211.0670314913395
 ]
]
}"

After parsing, I get this array of arrays. How can I separate the times from the prices while keeping them in the correct order so that I can create a chart with [Times] as the x-axis and [Prices] as the y?

I am thinking something like this:

var times: [Int] = [] // Will probably convert to traditional date for chart
var prices: [Double] = []

So I end up with:

print(times)
[1535837138223,1535837424517,1535837741575,...]
print(prices)
[5560.902754859002,5542.734892949798,5539.4334214537,...]

and can now set up my chart correctly. How can I do this? Alternatively, if there is a better way to set up my chart data, (I am using danielgindi/Charts for iOS) please let me know.

3
  • Show the json returned by your server Commented Sep 2, 2018 at 21:57
  • @LeoDabus sorry, the first part of code in the question is what is returned from the server. I will edit and add in full any other details it returns Commented Sep 2, 2018 at 22:03
  • @LeoDabus edited to what console shows when printing the response. If someone can give the reason for the downvote so that I can improve, thank you. Commented Sep 2, 2018 at 22:43

1 Answer 1

1

You need to structure your data and create a custom encoder/decoder to encode/decode your array of different data types UInt64 (epoch unix time) and Double (price):

struct Root: Codable {
    let prices: [Price]
}
struct Price: Codable {
    let date: Date
    let price: Double
}

extension Price {
    public init(from decoder: Decoder) throws {
        var unkeyedContainer = try decoder.unkeyedContainer()
        let date = try unkeyedContainer.decode(UInt64.self).date
        let price = try unkeyedContainer.decode(Double.self)
        self.init(date: date, price: price)
    }
    public func encode(to encoder: Encoder) throws {
        var unkeyedContainer = encoder.unkeyedContainer()
        try unkeyedContainer.encode(date.unixEpochTime)
        try unkeyedContainer.encode(price)
    }
}

extension UInt64 {
    var date: Date {
        return Date(timeIntervalSince1970: TimeInterval(self)/1000)
    }
}
extension Date {
    var unixEpochTime: UInt64 {
        return UInt64(timeIntervalSince1970*1000)
    }
}

Playground testing:

let json = """
{"prices": [[1535837138223,5560.902754859002],
            [1535837424517,5542.734892949798],
            [1535837741575,5539.4334214537]]}
"""

do {
    let prices = try JSONDecoder().decode(Root.self, from: Data(json.utf8)).prices
    print(prices.first!.date.description(with:.current))  // "Saturday, September 1, 2018 at 6:25:38 PM Brasilia Standard Time\n"
    print(prices.first!.price)  // "5560.902754859\n"

} catch {
    print(error)
}
Sign up to request clarification or add additional context in comments.

4 Comments

very helpful thank you. I think I understand what is going on, just to be clear here try JSONDecoder().decode(Root.self, from: Data(json.utf8)), i will put my responseJSON like: try JSONDecoder().decode(Root.self, from: Data(responseJSON.utf8)) correct? I will try it the morning and let you know.
Just replace Data(json.utf8) with the data response response.data from your alamofire request inside your success case.
Works perfectly, I am just now trying to figure out how to get all of the values and add to a new array, as I can only access them individually. How would I print all prices in the prices struct for example, or append an array with all values in prices.price, as I can only access prices.first!.price or prices.last!.price.
I've got it, 'for element in prices { print(element.price) }'

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.