First time I'm trying to parse JSON data. The output comes out -
Course (success: zero, timestamp: nil, base: nil, date: nil, courses: nil)
Why is there nil everywhere?
I tried to change the value in the "Course" and "Currency" structures but did not lead to success
import UIKit
import JavaScriptCore
struct Course: Decodable {
var success: Bool?
var timestamp: Int?
var base: String?
var date: String?
var rates: Currency?
}
struct Currency: Decodable {
var USD: Float
var AUD: Double
var CAD: Double
var PLN: Double
var MXN: Double
}
class JsonViewContoller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let urlData: String = "http://data.fixer.io/api/latest?access_key=7ac2982c82da926b787fd2f089b110e5&symbols=USD,AUD,CAD,PLN,MXN&format=1"
guard let url = URL(string: urlData) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
guard error == nil else { return }
do {
let course = try JSONDecoder().decode(Course.self, from: data)
print(Course())
} catch let error {
print(error)
}
}.resume()
}
}
I have run your code you don't need to use two structures to parse the above JSON data. You can easily get Data in a single Structure. I have modified your code as follows:-
import UIKit
struct Course: Codable {
let success: Bool?
let timestamp: Int?
let base, date: String?
let rates: [String: Double]?
}
class JsonViewContoller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
courseData()
}
fileprivate func courseData(){
let urlData: String = "http://data.fixer.io/api/latest?access_key=7ac2982c82da926b787fd2f089b110e5&symbols=USD,AUD,CAD,PLN,MXN&format=1"
guard let url = URL(string: urlData) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
guard error == nil else { return }
do {
let course = try JSONDecoder().decode(Course.self, from: data)
print(course)
} catch let error {
print(error)
}
}.resume()
}
}
Related
I have a call api function and parameter using generic types.
And I alse craete codable data model.
Why the function parameter don't get my custom struct model and get the error Cannot find 'ModelA' in scope.
Is my T type error?
I don't know how to fix it.
Thanks.
struct ResponseHeader :Codable {
let returnCode : String?
let returnMsg : String?
}
struct ModelA :Codable {
let responseHeader : ResponseHeader?
let responseBody : ResponseBody?
struct ResponseBody: Codable {
let name : String?
let age : String?
let email: String?
}
}
enum APIRouter: String {
case apiA = "http://localhost:3000/ApiA"
case apiB = "http://localhost:3000/ApiB"
case apiC = "http://localhost:3000/ApiC"
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.callApi(apiRouter: .apiA, model: ModelA) //Error. Cannot find 'ModelA' in scope
}
func callApi<T: Codable>(apiRouter: APIRouter, model: T.Type) {
let urlString = URL(string: apiRouter.rawValue)
if let url = urlString {
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error == nil else { return }
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let data = data {
do {
let response = try decoder.decode(model.self, from: data)
print(response)
} catch {
print(error)
}
} else {
print("Error")
}
}
task.resume()
}
}
}
Add self at the end.
This generic function takes as an argument an Instance Type of model so you have to pass ModelA.self.
self.callApi(apiRouter: .apiA, model: ModelA.self) //Here
I'm trying to play around with a COVID dataset from Github (link in code below) but when I run the code nothing appears in the console. There are no errors appearing.
Can anyone advise on whats wrong here? Thanks in advance!
struct country: Decodable {
var location: String
var new_cases: Double
var people_fully_vaccinated: Double
}
func getJSON(){
guard let url = URL(string: "https://raw.githubusercontent.com/owid/covid-19-data/68c39808d445fe90b1fe3d57b93ad9be20f796d2/public/data/latest/owid-covid-latest.json") else{
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request){ (data, response, error) in
if let error = error{
print(error.localizedDescription)
return
}
guard let data = data else{
return
}
let decoder = JSONDecoder()
guard let decodedData = try? decoder.decode([country].self, from: data) else{
return
}
let countries = decodedData
for country in countries{
print (country.location)
}
}.resume()
}
getJSON()
You need
struct Root: Decodable {
var location: String
var new_cases: Double? // make it optional as it has some objects with nil
var people_fully_vaccinated: Double? // make it optional as it has some objects with nil
}
With
do {
let res = try decoder.decode([String:Root].self, from: data)
let locations = Array(res.values).map { $0.location }
print(locations)
}
catch {
print(error)
}
I have an API response that is stored in a dictionary, I have created structs in a different folders but when I try to decode them using decode method it throws an error, the error mentions that "The data couldn’t be read because it isn’t in the correct format." , here is the code and structs I have built:
import UIKit
class ViewController: UIViewController {
#IBOutlet var cityButtons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func handleSelection(_ sender: UIButton) {
cityButtons.forEach{ (button) in
UIView.animate(withDuration: 0.3) {
button.isHidden = !button.isHidden
self.view.layoutIfNeeded()
}
}
}
enum Cities:String {
case amman = "Amman"
case azzerqa = "Az zerqa"
case irbid = "Irbid"
case aqaba = "Aqaba"
}
#IBAction func cityTapped(_ sender: UIButton) {
guard let title = sender.currentTitle, let City = Cities(rawValue: title)
else {
return
}
var city:String
switch City {
case .amman:
city = "Amman"
case .azzerqa:
city = "zerqa"
case .irbid:
city = "Irbid"
case .aqaba:
city = "Aqaba"
}
let url = URL(string: "https://api.weatherapi.com/v1/current.json?key={ket}&q=\(city)")
guard url != nil else {
print("error creating URL Object")
return
}
var request = URLRequest(url: url!, cachePolicy: .useProtocolCachePolicy , timeoutInterval: 10)
let headers = ["Content-Type" : "application/json"]
request.allHTTPHeaderFields = headers
request.httpMethod = "GET"
let session = URLSession.shared
let dataTask = session.dataTask(with: request) {(data, response, error) in
if error == nil && data != nil {
do {
let dictionary = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String:Any]
let decoder = JSONDecoder()
print(dictionary)
do {
let weatherdatadecoded = try decoder.decode(WeatherData.self, from: data!)
print(weatherdatadecoded)
}
catch {
print(error.localizedDescription)
}
}
catch {
print(error.localizedDescription)
}
}
}
dataTask.resume()
}
}
and here are the structs (each one is in a separate file):
import Foundation
struct WeatherData : Codable {
var location: Location?
var current: Current?
}
import Foundation
struct Location : Codable {
var name: String = ""
var region: String = ""
var localtime: String = ""
var country: String = ""
}
import Foundation
struct Current : Codable {
var temp_c = 0.0
var is_day = false
var condition: Condition?
}
import Foundation
struct Condition : Codable {
var text: String = ""
var icon: String = ""
var code: Int = 0
}
Im calling this api to receive single rocket launch event:
https://launchlibrary.net/1.4/launch/next/1 using simple Get request.
Trying to decode using SwiftyJson (also tried Codable) with lack of success to read the "rocket" -> "imageURL"
here is my code:
struct LaunchHistory {
var launches = [LaunchItem]()
init(with json:JSON) {
for launch in json["launches"].arrayValue {
let launchItem = LaunchItem(with: launch)
launches.append(launchItem)
}
}
}
struct LaunchItem {
let id:Int?
let name: String?
let tbddate: Int?
let status: LaunchStatus?
let rocketImage: String?
init(with json:JSON) {
self.id = json["id"].int
self.name = json["name"].string
self.tbddate = json["tbddate"].int
self.status = LaunchStatus(rawValue: json["status"].int ?? 0)
self.rocketImage = json["rocket"]["imageURL"].string
}
}
when LaunchItem decoded, all i 11 properties/key instead of almost double.
the rocket object is missing.
what am i missing here?
thanks!
It's pretty easy with (De)Codable
struct Root : Decodable {
let launches : [LaunchItem]
}
struct LaunchItem : Decodable {
let id: Int
let name: String
let tbddate: Int
let rocket: Rocket
}
struct Rocket : Decodable {
let imageURL : URL
}
let url = URL(string: "https://launchlibrary.net/1.4/launch/next/1")!
let task = URLSession.shared.dataTask(with: url) { (data, _, error) in
if let error = error { print(error); return }
do {
let result = try JSONDecoder().decode(Root.self, from: data!)
print(result.launches.first?.rocket.imageURL ?? "n/a")
} catch {
print(error)
}
}
task.resume()
I am trying to display information taken from JSON. I've used .decode to get it. Now I want to put its text onto a simple label on my storyboard. At the bottom under ".resume()" is my attempt and it isn't working. I can't seem to figure this out.
import UIKit
struct WebsiteDescription: Decodable {
var name : String
var description : String
var courses : [Course]
}
struct Course: Decodable {
let id: Int
let name: String
let link: String
let imageUrl: String
}
class ViewController: UIViewController {
#IBOutlet weak var displayLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let jsonUrlString = "https://api.letsbuildthatapp.com/jsondecodable/website_description"
guard let url = URL(string: jsonUrlString) else {return}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {return}
do {
let websiteDescription = try JSONDecoder().decode(WebsiteDescription.self, from: data)
print(websiteDescription.name, websiteDescription.description, websiteDescription.courses)
//let courses = try JSONDecoder().decode([Course].self, from: data)
} catch let jsonErr {
print("Error serializing json", jsonErr)
}
}.resume()
let displayLabel.text = websiteDescription.name
}
}
You need to update your label from within the do method. Also you should do it from the main thread so that the UI can be updated. I have updated the code below.
import UIKit
struct WebsiteDescription: Decodable {
var name : String
var description : String
var courses : [Course]
}
struct Course: Decodable {
let id: Int
let name: String
let link: String
let imageUrl: String
}
class ViewController: UIViewController {
#IBOutlet weak var displayLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let jsonUrlString = "https://api.letsbuildthatapp.com/jsondecodable/website_description"
guard let url = URL(string: jsonUrlString) else {return}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {return}
do {
let websiteDescription = try JSONDecoder().decode(WebsiteDescription.self, from: data)
print(websiteDescription.name, websiteDescription.description, websiteDescription.courses)
//let courses = try JSONDecoder().decode([Course].self, from: data)
DispatchQueue.main.async {
self.displayLabel.text = websiteDescription.name
}
} catch let jsonErr {
print("Error serializing json", jsonErr)
}
}.resume()
}