Decoding Nested Json, Missing objects using SwiftyJson iOS - ios

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()

Related

Cannot find 'ModelA' in scope using generic types

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

Nothing appearing the console when Decoding JSON in Swift

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)
}

JSON throws nil on every request

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()
}
}

Swift decodable can't access nested data in array

I get a critical error stating the following. I've tried everything but I can't seem to access the Movie struct as it says the parent 'Type' has no member called 'data', even though it clearly does.
"Value of type '[Type?]' has no member 'data'"
MODEL
struct SearchData: Decodable {
let data: [Type?]
}
struct Type: Decodable {
let data: [Movie?]
}
struct Movie: Decodable {
let title: String?
}
CONTROLLER
fileprivate var searchResults = [Movie?]()
func fetchTitles() {
let urlString = "https://www.what-song.com/api/search?limit=10&field=america"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
// if error occurs
if let err = err {
print("Failed to fetch titles", err)
return
}
// if success
guard let data = data else { return }
do {
let searchResult = try JSONDecoder().decode(SearchData.self, from: data)
self.searchResults = searchResult.data.data
print(searchResult)
} catch {
print("Failed to decode JSON:", error)
}
}.resume()
}
Try this :
var movieTitles = [String]()
for type in searchResult.data {
for movie in type.data {
guard let title = movie.title else { return }
print(title)
movieTitles.append(title)
}
}
you are doing a small mistake here I think
searchResult.data
will return you an array of
Type
You need to parse that array as well, something like this
searchResults = (searchResult.data[0]?.data)!

Could not decode JSON: The data couldn’t be read because it isn’t in the correct format

UPDATE
I get the error "Error! Could not decode JSON: The data couldn’t be read because it isn’t in the correct format.". The JSON from the request is
{"page":0,"pageSize":100,"totalPages":1,"numberOfElements":1,"totalElements":1,"hasPreviousPage":false,"hasNextPage":false,"content":[{"id":4554053904,"externalAccountId":null,"source":"PLAN","amount":1073741824,"reportId":null,"rowId":null,"timeCharged":1533427200000,"timeCreated":1533476043000}]}
Why is it not working?
I don't know how to get the answer...
My code and structure:
struct TodoItem: Decodable {
let page: Int?
let pageSize: Int?
let totalPages: Int?
let numberOfElements: Int?
let totalElements: Int?
let hasPreviousPage: Bool
let hasNextPage: Bool
let content: [content]
}
struct content: Decodable {
let id: Int?
let externalAccountId: String?
let source: String?
let amount: Int?
let reportId: Int?
let rowId: Int?
let timeCharged: Int?
let timeCreated: Int?
}
func decodeJson() {
let jsonUrlString = "myurl.com"
print(jsonUrlString)
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (mydata, response, error2) in
guard let datos = mydata else { return }
do {
self.todoList = try JSONDecoder().decode([TodoItem].self, from: datos)
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch let jsonError {
print("Error! Could not decode JSON: \(jsonError.localizedDescription)")
}
}.resume()
1 - You should cache data when the load finish to not reload when you scroll to this cell again
2 - You can show loading fullscreen when you load data of cell 0 -> 10 -> and reload tableview when finish all of them
3 - Instead of an update in the app, you can update from server to load many items in just 1 request
Hope useful for you
The question has nothing to do with the title anymore.
Anyway. Your JSON is not an array of TodoItem.

Resources