how to loop through structs? - json

I'm fetching data from coinDesk API to get bitcoin rate related to other currencies, I've created 3 structs to save this data, but it's not possible to loop through the struct to know how many items I have there...
that's my structure:
struct Response: Codable {
var bpi: currencies
}
struct currencies: Codable {
var USD: info
var GBP: info
var EUR: info
}
struct info: Codable {
var code: String
var symbol: String
var description: String
var rate_float: Float
}
To save the data from API I just use:
let jsonData = try JSONDecoder().decode(Response.self, from: data)
It saves the data with no error but, when I try to loop through this data to populate tableViewCells it doesn't work.
what I'm doing know is...
let euro = jsonData.bpi.EUR
let dollar = jsonData.bpi.USD
let gbp = jsonData.bpi.GBP
let infos = [euro,dollar,gbp]
completion(infos)
This is sending the data to my UITableView and populating, but what if I had 500 currencies? it would not be practical at all.. how could I do this in a more effective way?
Thank you in advance for the answers.

Don't put keys instead
struct Response: Codable {
let bpi: [String:Info]
}
struct Info: Codable {
let code: String
let symbol: String
let description: String
let rate_float: Float
}
Then
let jsonData = try JSONDecoder().decode(Response.self, from: data)
print(jsonData.bpi["USD"])
so for all keys
let keys = Array(jsonData.bpi.keys)
let values = Array(jsonData.bpi.values)

Related

Parse Json to nested Struct using Swift

I am trying to parse a JSON that I am receiving in my Application. The JSON Syntax is correct but I am unable to parse it into a nested Struct.
Here is my code that can be run in Playground:
let message = "{\"type\":\"something\",\"data\":{\"one\":\"first\",\"two\":\"second\",\"three\":\"third\"}}"
let jsonData = message.data(using: .utf8)!
struct Message: Decodable {
let type: String
struct data: Decodable {
var one: String
var two: String
var three: String
}
}
let receivedMessage: Message = try! JSONDecoder().decode(Message.self, from: jsonData)
The printed Result is Message(type: "something") but the data is not parsed.
How can I parse the data correctly to use it afterwards.
The nested struct/dictionary is the value for key data
struct Message: Decodable {
let type: String
let data: Nested
struct Nested: Decodable {
var one: String
var two: String
var three: String
}
}

Decode weird JSON to a normal struct?

To decode JSON, I had to create this struct:
struct Product: Decodable {
var title: String
var thumbnail: URL
var price: Price
var asin: String
}
struct Price: Decodable {
var current_price: Double
}
The decoder looks like this:
let product = try? JSONDecoder().decode(Product.self, from: data)
As you can see, JSON Price has nested property current_price, which is not very useful for me.
I have a few questions:
How can I get rid of Price and store it directly as double to Product?
Prop: thumbnail is a URL. I want to store it as a String. Is this possible?
You can try this
struct Product: Decodable {
var title: String
var thumbnail: String
var price: [String: Double]
var asin: String
var currentPrice: Double? { price["current_price"] }
}

Fetching city name from json with swift

I need help with proper parsing of OpenWeatherAPI. I need to fetch city name.
I always got this line of code:
021-09-23 08:16:13.526604+0200 Clima[1943:50811] Writing analzed variants.
Optional("")
This is my JSON:
JSON example
This is my struct for api:
struct WeatherData: Decodable{
let message: String?
let list: [List]?
}
struct List: Decodable{
let name: String?
}
And my function for fetching json:
func parseJSON(weatherData: Data) {
let decoder = JSONDecoder()
do{
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
print(decodedData.list![0].name!)
}catch{
print(error)
}
}
I need to fetch a name. I understand that I need to make in my main struct WeatherData let for another struct and then use it. E.g. decodedData.list.name to fetch some data.
One more question: should I always use ? (optional) when fetching data from JSON ?

Store TMDB API data

I'm working on an app that requires the use of the TMDB API. I have been trying to store the results from the API in a struct but it keeps giving me the error:
No exact matches in call to subscript
This is the struct:
struct MovieList: Codable {
let dates: Date?
let page: Int?
let results: [Result]?
let total_pages: Int?
let total_results: Int?
}
struct Result: Codable {
let adult: Bool?
let backdrop_path: String?
let genre_ids: [Int]?
let id: Int?
let original_language: String?
let original_title: String?
let overview: String?
let popularity: Int?
let poster_path: String?
let release_date: String?
let title: String?
let video: Bool?
let vote_average: Float?
let vote_count: Int?
And here is my API call:
public class LoadTMDBData {
var tmdbMoviesData = [[Result]]()
init() {
getTMDBData()
}
func getTMDBData() {
guard let url = URL(string: "") else {
fatalError("Invalid URL")
}
// Set session configuration to default
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { data, response, error in
// Check that data has been returned
guard let data = data else { return }
do {
let tmdbData = try JSONDecoder().decode([MovieList].self, from: data)
self.tmdbMoviesData = tmdbData["result"]
}
catch{
let error = error
print(error.localizedDescription)
}
}
// execute the HTTP request
task.resume()
}
When using a struct you don't access its properties using a string key like ["someProperty"], instead you use dot notation .someProperty, so to get the results property you do
let results = myMoveList.results
What makes it a little more complicated here is that you have, as you properly have coded for, an array of MovieList and that you want to extract all results into an array for array.
For this you can use a high order function map to do this
self.tmdbMoviesData = tmdbData.map(\.results)
but since results is optional we use a similar function that will filter out any nil values, compactMap
self.tmdbMoviesData = tmdbData.compactMap(\.results)
Another comment, you have made all properties optional in your structs and while this is an easy way forward it might lead to hiding some decoding issues and more cumbersome code when using the types. I would recommend not to use optional unless really needed.

Save JSON String in Object

i want to save a JSON-String into an existing Object in Swift:
This is my Object:
struct Benutzer : Decodable, Encodable{
let userRights: [String]
}
This is my String:
str = "{"user_rights":["terminal_create"]}"
That is my Code:
do { let data1 = str.data(using: String.Encoding.utf8, allowLossyConversion: false)
let User = try JSONDecoder().decode(Benutzer.self, from: data1 as Data)
print(User)
}catch{
print("Error serializing!")
}
With this code, "Error serializing!" shows up every time. Do you guys know whats up? Sorry, I am still a complete beginner. Sorry for not formatting the question I don't quite get it :( I get this String from another JSON request: I get this as an answer, the JSON data string that I want to decode is part of that answer:
Answer(api_version: 1, result: "login", success: true, token: "da39a3ee5e6b4b0d3255bfef95601890afd80709", data: "{\"user_rights\":[\"terminal_create\"]}")
This is a Answer-Object:
struct Answer: Decodable, Encodable{
let api_version: Int
let result: String
let success: Bool
let token: String
let data: String
}
Maybe you know another way how to extract that Data into a Benutzer Object.
I would be really thankful, thanks a lot guys!
your coding key not similar to what in your string userRights , user_rights
so do like that:
struct Benutzer: Codable {
let userRights: [String]
enum CodingKeys: String, CodingKey {
case userRights = "user_rights"
}
}