Array JSON decoding in swift - json

I am trying to decode this json array and I got the following code to work, initially but it is a bit buggy.
the json is structured as following:
{
"prices": [
[
1595642361269,
180.62508267006177
],
[
1596642361269,
190.1
]
],
"market_caps": [
[
1595642361269,
3322122955.6677375
],
[
1596642361269,
3332122955.6677375
]
],
"total_volumes": [
[
1595642361269,
590499490.5115521
],
[
1595642361269,
590499490.5115521
]
]
}
my swift object is structured as:
struct MarketChart: Decodable {
let prices: [[Double]]
let market_caps: [[Double]]
let total_volumes: [[Double]]
}
I dont think it is optimal but as the json doesn't have keys for the timestamps and values I was a bit confused on how to structure it.
the following is my playground code:
func getJSON<T: Decodable>(urlString: String, completion: #escaping (T?) -> Void) {
guard let url = URL(string: urlString) else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
guard let decodedData = try? decoder.decode(T.self, from: data) else {
completion(nil)
return
}
completion(decodedData)
}.resume()
}
struct MarketChart: Decodable {
let prices: [[Double]]
let market_caps: [[Double]]
let total_volumes: [[Double]]
}
var priceArray: [Double] = []
print(priceArray)
getJSON(urlString: "https://api.coingecko.com/api/v3/coins/bitcoin-cash-sv/market_chart?vs_currency=usd&days=1") { (data: MarketChart?) in
if let data = data {
for item in data.prices {
priceArray.append(item.first!)
}
}
}
print(priceArray)
I am trying to get all the values into an array and it did work initially but now just keeps printing an empty array. my end goal is to crate a graph of the values over time in a project and I did it successfully the first time but now I keep getting an error saying it can't get the value from an empty array.
my Xcode project file is as follows:
import SwiftUI
import SwiftUICharts
import Combine
struct CoinGeckoBSVMarketChart: View {
#State var jsonData = [MarketChart]()
#State var priceArray = [Double]()
#State var volumeArray: [Double] = []
private let last24hpricesURL: String = "https://api.coingecko.com/api/v3/coins/bitcoin-cash-sv/market_chart?vs_currency=usd&days=1"
var body: some View {
ZStack {
VStack {
LineView(data: priceArray)
.padding()
Text("Reset")
.onTapGesture {
}
}
}
.onAppear {
getJSON(urlString: last24hpricesURL) { (data: MarketChart?) in
if let data = data {
for item in data.prices {
priceArray.append(item.last!)
}
}
}
}
}
}
struct MarketChart: Decodable {
let prices: [[Double]]
let market_caps: [[Double]]
let total_volumes: [[Double]]
}
struct CoinGeckoBSVMarketChart_Previews: PreviewProvider {
static var previews: some View {
CoinGeckoBSVMarketChart()
.preferredColorScheme(.dark)
}
}
any help with either improving the json object model or getting all the items in an array would be great

You have to print out the priceArray inside the completion block of getJSON method right after appending.
getJSON(urlString: "https://api.coingecko.com/api/v3/coins/bitcoin-cash-sv/market_chart?vs_currency=usd&days=1") { (data: MarketChart?) in
if let data = data {
for item in data.prices {
priceArray.append(item.first!)
}
print(priceArray)
}
}

Related

Swift - How to decode a JSON path that looks like this 0.lat

I would like to get the position data of a city from the openweathermap Geocoding API
But I have a problem with there Json struct and that the path starts with a 0
like this: 0.lat
here is an example of the JSON I get back
[
{
"name": "Osimo",
"local_names": {
"ru": "Озимо",
"fr": "Osime",
"it": "Osimo"
},
"lat": 43.4861359,
"lon": 13.4824068,
"country": "IT",
"state": "Marche"
}
]
And this is my code. I found CodingKey when I was looking up the problem but it doesn't work in my code or I did made a mistake.
PositionData.swift
enum CodingKeys: String, CodingKey {
case zero = "0"
}
struct PositionData: Decodable {
let zer0: Zero
}
struct Zero: Decodable {
But when I would like to code the path it tells me that: Value of type 'PositionData' has no member '0'
LocationManager.Swift
do {
let decodedData = try decoder.decode(PositionData.self, from: positionData)
print(decodedData.0.lat)
} catch {
print("Error in Json")
I tried to load the position data of the openweathermap Geocoding API.
Now I am not sure how to decode the JSON data with a path like this 0.lat
There is no the path starts with a 0.
You have to decode an array and get the item at index zero
do {
let decodedData = try decoder.decode([PositionData].self, from: positionData)
print(decodedData[0].lat) // better print(decodedData.first?.lat)
} catch {
print(error) // NEVER print a literal like ("Error in Json")
}
and delete
enum CodingKeys: String, CodingKey {
case zero = "0"
}
struct PositionData: Decodable {
let zer0: Zero
}
struct Zero: Decodable {
PositionData must look like
struct PositionData: Decodable {
let lat, lon: Double
// ...
}
You could specifically send only the data at position 0 to the json decoder or your could fetch and decode the entire array and show only the data at position 0, it's really upto you.
Client
class APIManager {
static let shared = APIManager()
func fetchWeatherData(url: URL, completionHandler: #escaping ([PositionData]?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
if let data {
do {
let json = try? JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed) as? [String: Any]
if let json = json {
completionHandler([PositionData(json)], nil)
}
}
} else {
completionHandler(nil, error)
}
})
task.resume()
}
}
Model
struct PositionData: Decodable {
var id: UUID
var lat: Double
var lon: Double
init(_ data: [String : Any]) {
id = UUID()
lat = data["lat"] as? Double ?? 0
lon = data["lon"] as? Double ?? 0
}
}
View
struct MyView: View {
let url = URL(string: "www.weatherData.com")
#State var weatherData: [PositionData]?
var body: some View {
VStack {
if let weatherData {
if !weatherData.isEmpty {
Text("lat: \(weatherData[0].lat), lon: \(weatherData[0].lon)")
}
}
}
.onAppear {
if let url {
fetchWeather(url: url)
}
}
}
}
ViewModel
extension MyView {
func fetchWeather(url: URL) {
APIManager.shared.fetchWeatherData(url: url) { data, error in
if let data {
for datum in data {
weatherData.append(datum)
}
} else {
print(error?.localizedDescription)
}
}
}
}

Fetch data from nested JSON API in SwiftUI (object in array in object in another object)

Beginner here, in a bit over my head with this. ;)
I've found examples that have shown me how to get data from a JSON API feed if the feed is structured as an array of objects, but I don't know how to approach getting the data (specifically, url and title) if the data I'm retrieving comes back in a more complex nested structure like this one:
{
"races": {
"videos": [{
"id": 1,
"url": "firsturl",
"title": "1st Video Title"
}, {
"id": 2,
"url": "secondurl",
"title": "2nd Video Title"
}]
}
}
I've succeeded at get data from another API feed that's structured as a simple array of objects--it's like what's above but without the extra two lead-in objects, namely this: { "races": { "videos":
Here's the code I pieced together from a few examples that worked for the simple array:
import SwiftUI
struct Video: Codable, Identifiable {
public var id: Int
public var url: String
public var title: String
}
class Videos: ObservableObject {
#Published var videos = [Video]()
init() {
let url = URL(string: "https://exampledomain.com/jsonapi")!
URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
if let videoData = data {
let decodedData = try JSONDecoder().decode([Video].self, from: videoData)
DispatchQueue.main.async {
self.videos = decodedData
}
} else {
print("no data found")
}
} catch {
print("an error occurred")
}
}.resume()
}
}
struct VideosView: View {
#ObservedObject var fetch = Videos()
var body: some View {
VStack {
List(fetch.videos) { video in
VStack(alignment: .leading) {
Text(video.title)
Text("\(video.url)")
}
}
}
}
}
I've spent several hours over a few days reading and watching tutorials, but so far nothing is sinking in to help me tackle the more complex JSON API feed. Any tips would be greatly appreciated!
UPDATE:
With the help of a Swift Playground tutorial and the suggested structs mentioned in the comments below, I've succeeded at retrieving the more complex data, but only in Swift Playgrounds, using this:
import SwiftUI
struct Welcome: Codable {
let races: Races
}
struct Races: Codable {
let videos: [Video]
}
struct Video: Codable {
let id: Int
let url, title: String
}
func getJSON<T: Decodable>(urlString: String, completion: #escaping (T?) -> Void) {
guard let url = URL(string: urlString) else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
let decoder = JSONDecoder()
guard let decodedData = try? decoder.decode(T.self, from: data) else {
completion(nil)
return
}
completion(decodedData)
}.resume()
}
getJSON(urlString: "https://not-the-real-domain.123/api/") { (followers:Welcome?) in
if let followers = followers {
for result in followers.races.videos {
print(result.title )
}
}
}
Now, I'm struggling with how to properly integrate this Playgrounds snippet in to the working SwiftUI file's VideosViews, etc.
UPDATE 2:
import SwiftUI
struct Welcome: Codable {
let races: RaceItem
}
struct RaceItem: Codable {
let videos: [VideoItem]
}
struct VideoItem: Codable {
let id: Int
let url: String
let title: String
}
class Fetcher: ObservableObject {
func getJSON<T: Decodable>(urlString: String, completion: #escaping (T?) -> Void) {
guard let url = URL(string: urlString) else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
let decoder = JSONDecoder()
guard let decodedData = try? decoder.decode(T.self, from: data) else {
completion(nil)
return
}
completion(decodedData)
}.resume()
}
}
struct JSONRacesView: View {
#ObservedObject var fetch = Fetcher()
getJSON(urlString:"https://not-the-real-domain.123/api/") { (followers:Welcome?) in
if let followers = followers {
for result in followers.races.videos {
print(result.title )
}
}
}
var body: some View {
VStack {
List(fetch.tracks) { track in
VStack(alignment: .leading) {
Text(track.title)
Text("\(track.url)")
}
}
}
}
There's a great site called QuickType (app.quicktype.io) where you can paste in some JSON and get the Swift structs generated for you. Here's what it gives you:
import Foundation
// MARK: - Welcome
struct Welcome: Codable {
let races: Races
}
// MARK: - Races
struct Races: Codable {
let videos: [Video]
}
// MARK: - Video
struct Video: Codable {
let id: Int
let url, title: String
}
They have a bug in their template generator that mangles the demo line (I've submitted a pull request that is merged but isn't live on the site at the time of this writing), but here's what it should look like:
let welcome = try? JSONDecoder().decode(Welcome.self, from: jsonData)
Using do/try so you can catch the errors, you can decode the data and reach the lower levels by doing:
do {
let welcome = try JSONDecoder().decode(Welcome.self, from: jsonData)
let videos = welcome.races.videos //<-- this ends up being your [Video] array
} catch {
//handle any errors
}
Update, based on your comments and updates:
You chose to go a little bit of a different route than my initial suggestion, but that's fine. The only thing that I would suggest is that you might want to deal with handling errors at some point rather than just returning nil in all of the completions (assuming you need to handle errors -- maybe it just not loading is acceptable).
Here's a light refactor of your code:
class Fetcher: ObservableObject {
#Published var tracks : [VideoItem] = []
private func getJSON<T: Decodable>(urlString: String, completion: #escaping (T?) -> Void) {
guard let url = URL(string: urlString) else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
let decoder = JSONDecoder()
guard let decodedData = try? decoder.decode(T.self, from: data) else {
completion(nil)
return
}
completion(decodedData)
}.resume()
}
func fetchData() {
getJSON(urlString:"https://not-the-real-domain.123/api/") { (followers:Welcome?) in
DispatchQueue.main.async {
self.tracks = followers?.races.videos ?? []
}
}
}
}
struct JSONRacesView: View {
#StateObject var fetch = Fetcher()
var body: some View {
VStack {
List(fetch.tracks, id: \.id) { track in
VStack(alignment: .leading) {
Text(track.title)
Text("\(track.url)")
}
}
}.onAppear {
fetch.fetchData()
}
}
}
You can see that now Fetcher has a #Published property that will store the tracks ([VideoItem]). getJSON is still in fetcher, but now it's private just to show that it isn't meant to be called directly. But, now there's a new function called fetchData() that your view will call. When fetchData gets data back, it sets the #Published property to that data. I used the ?? operator to tell the compiler that if followers is nil, then just use [] instead. This is all in a DispatchQueue.main.async block because the URL call is probably not going to return on the main thread and we need to make sure to always update the UI on the main thread (Xcode will warn you about this at runtime if you update the UI on a different thread).
JSONRacesView calls fetchData in onAppear, which happens exactly when it sounds like it will.
Last thing to note is I used #StateObject instead of #ObservedObject. If you're not on iOS 14 or macOS 11 yet, you could use #ObservedObject instead. There are some differences outside the scope of this answer, but that are easily Google-able.

SwiftyJSON convert string array to array not working

I have data as below:
data =
[
"\u65b0\u5317\u5e02\u4e09\u91cd\u5340","\u65b0\u5317\u5e02\u6c38\u548c\u5340",
"\u53f0\u5317\u5e02\u4e2d\u5c71\u5340","\u53f0\u5317\u5e02\u4e2d\u6b63\u5340",
"\u53f0\u5317\u5e02\u4fe1\u7fa9\u5340","\u53f0\u5317\u5e02\u5357\u6e2f\u5340",
"\u53f0\u5317\u5e02\u5927\u540c\u5340","\u53f0\u5317\u5e02\u5927\u5b89\u5340",
"\u53f0\u5317\u5e02\u6587\u5c71\u5340","\u53f0\u5317\u5e02\u677e\u5c71\u5340",
"\u53f0\u5317\u5e02\u842c\u83ef\u5340"
]
but when I want to convert it to array, I use the code:
data.array
it always give me nil, what can I do?
I've also tried data.arrayValue and data.arrayValue.map {$0.stringValue}
Assume your data construct is
[
{
"data": [
"\u65b0\u5317\u5e02\u4e09\u91cd\u5340",
"\u65b0\u5317\u5e02\u6c38\u548c\u5340",
"\u53f0\u5317\u5e02\u4e2d\u5c71\u5340",
"\u53f0\u5317\u5e02\u4e2d\u6b63\u5340",
"\u53f0\u5317\u5e02\u4fe1\u7fa9\u5340",
"\u53f0\u5317\u5e02\u5357\u6e2f\u5340",
"\u53f0\u5317\u5e02\u5927\u540c\u5340",
"\u53f0\u5317\u5e02\u5927\u5b89\u5340",
"\u53f0\u5317\u5e02\u6587\u5c71\u5340",
"\u53f0\u5317\u5e02\u677e\u5c71\u5340",
"\u53f0\u5317\u5e02\u842c\u83ef\u5340"
]
}
]
Convert JSON into entity meanwhile conform Codable Protocol
typealias DistEntity = [Dist]
struct Dist: Codable {
let data: [String]
}
Implementation model layer
protocol JSONFetcher: AnyObject {
func distParser(forResource fileName: String, completionHandler handler: #escaping((Result<DistEntity, Error>) -> ()))
}
class ModelLayer: JSONFetcher {
enum ParserError: Error {
case PathNotFound
case ConvertsObjectError
case DecoderError
}
func distParser(forResource fileName: String, completionHandler handler: #escaping((Result<DistEntity, Error>) -> ())) {
guard let url = Bundle.main.url(forResource: fileName, withExtension: "json") else { return handler(.failure(ParserError.PathNotFound)) }
guard let jsonData = try? Data(contentsOf: url) else { return handler(.failure(ParserError.ConvertsObjectError)) }
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
guard let distEntity: DistEntity = try? decoder.decode(DistEntity.self, from: jsonData) else { return handler(.failure(ParserError.DecoderError)) }
handler(.success(distEntity))
}
}
Preliminary parse in the interface of business logic layer
final class viewModel {
private var fetcher: JSONFetcher
init(fetcher: JSONFetcher = ModelLayer()) {
self.fetcher = fetcher
}
private func distParser() {
self.fetcher.distParser(forResource: "YourJSONFileName") { (result) in
switch result {
case .success(let entity):
print("[Dist Entity]: \(entity)")
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
Can't make sure that's useful for your scenario,
If no solve, may you should provide more detail info.

Empty List from JSON in SwiftUI

I'm having some trouble fetching data from the PiHole API;
This is the JSON format (from the url http://pi.hole/admin/api.php?summary):
{
"domains_being_blocked": "1,089,374",
"dns_queries_today": "34,769",
"ads_blocked_today": "11,258",
"ads_percentage_today": "32.4",
"unique_domains": "9,407",
"queries_forwarded": "17,972",
"queries_cached": "5,539",
"clients_ever_seen": "35",
"unique_clients": "23",
"dns_queries_all_types": "34,769",
"reply_NODATA": "1,252",
"reply_NXDOMAIN": "625",
"reply_CNAME": "10,907",
"reply_IP": "21,004",
"privacy_level": "0",
"status": "enabled",
"gravity_last_updated": {
"file_exists": true,
"absolute": 1588474361,
"relative": {
"days": "0",
"hours": "14",
"minutes": "18"
}
}
}
This is my code:
ContentView.swift
import SwiftUI
struct NetworkController {
static func fetchData(completion: #escaping (([PiHole.Stat]) -> Void)) {
if let url = URL(string: "http://pi.hole/admin/api.php?summary") {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
let stat = try? JSONDecoder().decode(PiHole.self, from: data)
completion(stat?.stats ?? [])
}
}.resume()
}
}
}
class ContentViewModel: ObservableObject {
#Published var messages: [PiHole.Stat] = []
func fetchData() {
NetworkController.fetchData { messages in
DispatchQueue.main.async {
self.messages = messages
}
}
}
}
struct ContentView: View {
#ObservedObject var viewModel = ContentViewModel()
var body: some View {
List {
ForEach(viewModel.messages, id: \.self) { stat in
Text(stat.domains_being_blocked)
}
}.onAppear{
self.viewModel.fetchData()
}
}
}
Data.swift
struct PiHole: Decodable {
var stats: [Stat]
struct Stat: Decodable, Hashable {
var domains_being_blocked: String
var ads_percentage_today: String
var ads_blocked_today: String
var dns_queries_today: String
}
}
Everything seems okay, no errors, yet when I run it, the simulator only shows an empty list
In Playground I can retrieve those data just fine:
import SwiftUI
struct PiHoleTest: Codable {
let domains_being_blocked: String
let ads_blocked_today: String
}
let data = try! Data.init(contentsOf: URL.init(string: "http://pi.hole/admin/api.php?summary")!)
do {
let decoder: JSONDecoder = JSONDecoder.init()
let user: PiHoleTest = try decoder.decode(PiHoleTest.self, from: data)
print("In Blocklist \(user.domains_being_blocked)")
print("Blocked Today: \(user.ads_blocked_today) ")
} catch let e {
print(e)
}
The Output:
In Blocklist 1,089,374
Blocked Today: 11,258
What am I doing wrong? Or better, is there another way to fetch these stats?
Thanks in Advance!
The issue was related to the structure. Your JSON decoded were not an array. So PiHole struct was unnecessary. I can tested and this code is working now.
import SwiftUI
struct NetworkController {
static func fetchData(completion: #escaping ((Stat) -> Void)) {
if let url = URL(string: "http://pi.hole/admin/api.php?summary") {
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
if let data = data {
let stat = try JSONDecoder().decode(Stat.self, from: data)
DispatchQueue.main.async() {
completion(stat)
}
return
} else {
print("Error Found")
}
} catch let error as NSError {
print(error.localizedDescription)
}
}.resume()
}
}
}
class ContentViewModel: ObservableObject {
#Published var stat: Stat? = nil
func fetchData() {
NetworkController.fetchData { stat in
self.stat = stat
}
}
}
struct TestView: View {
#ObservedObject var viewModel = ContentViewModel()
var body: some View {
List {
Text(viewModel.stat?.domains_being_blocked ?? "No Data")
Text(viewModel.stat?.ads_blocked_today ?? "No Data")
Text(viewModel.stat?.ads_percentage_today ?? "No Data")
Text(viewModel.stat?.dns_queries_today ?? "No Data")
}.onAppear{
self.viewModel.fetchData()
}
}
}
struct Stat: Decodable, Hashable {
var domains_being_blocked: String
var ads_percentage_today: String
var ads_blocked_today: String
var dns_queries_today: String
}

Swift weather data from Openweathermap API?

From openweathermap api, I am getting below response.
{
"cod":"200",
"message":0,
"cnt":40,
"list":[
{
"dt":1587643200,
"main":{
"temp":289.78,
"feels_like":283.61,
"temp_min":289.03,
"temp_max":289.78,
"pressure":1014,
"sea_level":1014,
"grnd_level":1010,
"humidity":41,
"temp_kf":0.75
},
"weather":[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
"clouds":{
"all":94
},
"wind":{
"speed":6.75,
"deg":2
},
"sys":{
"pod":"d"
},
"dt_txt":"2020-04-23 12:00:00"
},
{
"dt":1587654000,
"main":{
"temp":289.66,
"feels_like":284.44,
"temp_min":289.34,
"temp_max":289.66,
"pressure":1013,
"sea_level":1013,
"grnd_level":1009,
"humidity":47,
"temp_kf":0.32
},
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04d"
}
],
"clouds":{
"all":67
},
"wind":{
"speed":5.9,
"deg":357
},
"sys":{
"pod":"d"
},
"dt_txt":"2020-04-23 15:00:00"
}
Then I write the code below to get wind data for any specific daytime(dt). I get the jsonresponse to the Any "list". But I can't get the wind data. I get the error
"Value of type 'Any' has no subscripts".
Also, I can't understand how can I get the wind data for dt=1587643200 and dt=1587654000 separately.
if let list = jsonresponse["list"] as? Any {
let wind = list["wind"] as? [String : Any],
print(wind)
}
This is a super simple example, this question is similar to your problem. I would like that you learn about Codable protocol to simplify and improve your code because of this way is super creepy.
let url = URL(string: "https://samples.openweathermap.org/data/2.5/history/city?id=2885679&type=hour&appid=b1b15e88fa797225412429c1c50c122a1")!
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Error with the response, unexpected status code: \(String(describing: response))")
return
}
guard let data = data else {
return
}
guard let dictionaryObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return
}
guard let list = dictionaryObj["list"] as? [[String: Any]] else {
return
}
if let first = list.first, let wind = first["wind"] {
print(wind)
}
}).resume()
Incase anyone further needs help, I wrote a small code segment—using Swift Codables—to get this done.
Note that I'm using Higher Order Functions in Swift to filter & print the required values. You can follow this tutorial if you need to know more about how they work..
let urlNew = "https://samples.openweathermap.org/data/2.5/history/city?id=2885679&type=hour&appid=b1b15e88fa797225412429c1c50c122a1"
struct WeatherResponse: Codable {
let message: String
let cod: String
let city_id: Int
let calctime: Double
let cnt: Int
let list: [WeatherCompositeObject]
struct WeatherCompositeObject: Codable {
let main: WeatherMainObject
let wind: WeatherWindObject
let clouds: WeatherCloudObject
let weather: [WeatherObject]
let dt: Int
struct WeatherMainObject: Codable {
let temp: Double
let humidity: Int
//You can add the other parameters as needed here
}
struct WeatherWindObject: Codable {
let speed: Double
let deg: Double
}
struct WeatherCloudObject: Codable {
let all: Int
}
struct WeatherObject: Codable {
let id: Int
let main: String
let description: String
}
}
}
class ApiContentDownloader {
func getCurrentWeather(url: String) {
URLSession.shared.dataTask(with: URL(string: url)!) { data, urlResponse, error in
let parser = ContentParser()
let result = parser.parseData(data: data!)
if let result = result {
print("Weather: \(result.message)")
print("DT values: \(result.list.map({ $0.dt})) ")
print("Wind values: \(result.list.map({ $0.wind.speed})) ")
print("Weather descriptions: \(result.list.map({ $0.weather.map( {$0.description} )})) ")
}
else {
print("Oops... Error occured")
}
}.resume()
}
}
class ContentParser {
func parseData(data: Data) -> WeatherResponse? {
var result: WeatherResponse? = nil
do {
let json = try JSONDecoder().decode(WeatherResponse.self, from: data)
result = json
}
catch {
print(error.localizedDescription)
}
return result
}
}
let downloader = ApiContentDownloader()
downloader.getCurrentWeather(url: urlNew)