-4

I'm a newbie to JSON. I've done a few readings but I'm still confused and I'm getting errors.

How do you parse the following data?

[{"symbol":"ALI","date":"1/22/2018","open":44.9000,"high":45.5000,"low":44.9000,"close":45.2000,"bid":45.1500,"ask":45.2000,"volume":6698800,"value":303245610.0000,"netForeign":-42279365.0000}]

I would like to get each string individually.

For instance: Symbol, Date, etc.

Any help would be greatly appreciated. Thanks!

As a reference, I tried the following solution but got an error: How to parse Json object in swift 3

Juma Orido
  • 481
  • 1
  • 4
  • 11

1 Answers1

5

In Swift 4 it's very straightforward with the Decodable protocol:

let jsonString = """
[{"symbol":"ALI","date":"1/22/2018","open":44.9000,"high":45.5000,"low":44.9000,"close":45.2000,"bid":45.1500,"ask":45.2000,"volume":6698800,"value":303245610.0000,"netForeign":-42279365.0000}]
"""

struct Item : Decodable {
    let symbol, date : String
    let open, high, low, close, bid, ask, value, netForeign : Double
    let volume : Int
}

do {
    let data = Data(jsonString.utf8)
    let result = try JSONDecoder().decode([Item].self, from: data)
    print(result)
} catch {
    print("error: ", error)
}

Or even with decoding the date string as Date

struct Item : Decodable {
    let symbol : String
    let date : Date
    let open, high, low, close, bid, ask, value, netForeign : Double
    let volume : Int
}

do {
    let data = Data(jsonString.utf8)
    let formatter = DateFormatter()
    formatter.dateFormat = "MM/dd/yyyy"
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .formatted(formatter)
    let result = try decoder.decode([Item].self, from: data)
    print(result)
} catch {
    print("error: ", error)
}

This is an example to put JSONDecoder and URLSession together:

let url = URL(string: "https://api.whatever...")!
URLSession.shared.dataTask(with:url) { (data, _, error) in
  if error != nil {
     print(error!)
  } else {
     do {
        let result = try JSONDecoder().decode([Item].self, from: data!)
        print(result)
    } catch {
        print("error: ", error)
    }
  }

}.resume()

Please learn to read JSON. It's pretty simple. There are only two collection types (array, dictionary) and four value types (string, number, bool and null). See also my answer in this question:

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Hi Vadian, thanks for the help! Sorry but I think I haven't made my question clear, but I am actually fetching the son file from the internet... – Juma Orido Feb 03 '18 at 17:45
  • Use `URLSession` to get the data. There are hundreds of examples here on SO for example in the linked question. In this case omit the line `let data = Data(jsonString.utf8)` and use the `data` returned from the `dataTask` – vadian Feb 03 '18 at 17:47
  • Hi Vadian, I tried using the solution on the link you provided but I got the ff. error: Could not cast value of type '__NSArrayI' to 'NSDictionary'. – Juma Orido Feb 03 '18 at 17:54
  • Do not use `JSONSerialization`. Pass the `data` to `JSONDecoder` in this answer. – vadian Feb 03 '18 at 17:56
  • Regarding your previous answer just now, how do I use the data returned from the dataTask? Sorry newbie here. I got the part `let urlString = https://api.forecast.io/forecast/apiKey/37.5673776,122.048951 let url = URL(string: urlString) URLSession.shared.dataTask(with:url!) { (data, response, error) in if error != nil { print(error) } else {` on my code, however, how do I put the value of the dataTask inside the `do { let data=`? – Juma Orido Feb 03 '18 at 18:00
  • Wow, I tried it and it works great! However, how do I "get" each data individually? For instance, I only want to get the "Symbol" item, is that possible? – Juma Orido Feb 03 '18 at 18:12
  • In terms of JSON, an *object* or *item* is everything between `{ }`. Your JSON is an array `[]` of items containing values for `symbol`, `date` etc.. To get only the `symbol` value declare only the line `let symbol : String` in the struct. If you mean to get the values individually use a loop: `for item in result { print(item.symbol, item.date) }` – vadian Feb 03 '18 at 18:18
  • Hi Vadian, I greatly appreciate you helping me. I tried doing it and I got the ff. printed: `[MyApp.ViewController.Symbol(symbol: "ALI")` around eight times... I only need to have the word ALI printed. I hope that's possible... Thanks a lot – Juma Orido Feb 03 '18 at 18:22
  • Sorry, I don't understand. Have you tried the `for` loop? – vadian Feb 03 '18 at 18:23
  • Hi Vadian, sorry my bad. I commented before you fully answered my question. I got it, I used the code and I got the word "ALI" eight times because there are eight items on the JSON file. I got it now. Thank you very much, you're a real genius! :) – Juma Orido Feb 03 '18 at 18:28