I have two JSON call functions that get clients data and invoice data. In my clients JSON response I have ID and name, etc. In my invoice response I have client ID.
I need to get the client ID from invoice and convert to the client name string.
In my ClientsViewController I've made a function called downloadClientsJSON
func downloadClientsJSON(completed: #escaping () -> ()) {
let url = URL(string: "http://ex.com/app/api/clientList/get")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
self.clients.removeAll()
self.clients = try JSONDecoder().decode([ClientsList].self, from: data!)
DispatchQueue.main.async {
completed()
}
} catch {
print ("Error")
}
}
}.resume()
}
And here is the ClientsList structure:
import Foundation
struct ClientsList:Decodable {
let name: String
let vatNumber: String
let address: String
let cap: String
let city: String
let prov: String
let tel: String
let email: String
}
Here is the JSON Response:
[{"id":1,"name":"DemoClient","vatNumber":"010101010101","address":"Demo Address, 1","cap":"01010","city":"DemoCity","prov":"DP","tel":"555-1112223","email":"demo#example.com"}]
In my InvoiceViewController I've made a function called downloadInvoicesJSON
func downloadJSON(completed: #escaping () -> ()) {
let url = URL(string: "http://ex.com/app/api/invoiceList/get")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
self.invoices.removeAll()
self.invoices = try JSONDecoder().decode([InvoiceList].self, from: data!)
DispatchQueue.main.async {
completed()
}
} catch {
print (error)
}
}
}.resume()
}
Here is the InvoiceList structure:
import Foundation
struct InvoiceList:Decodable {
let id: NSInteger
let date: String
let expiration: String
let client: NSInteger
let status: NSInteger
let lines: String
let total: Float
}
Here is the JSON Response:
[{"id":1,"date":"01-01-2018","expiration":"01-01-2018","client":3,"status":3,"lines":"1:1","total":700},{"id":2,"date":"30-01-2018","expiration":"30-01-2018","client":4,"status":2,"lines":"1:1","total":100},{"id":3,"date":"15-02-2018","expiration":"15-02-2018","client":3,"status":3,"lines":"1:1","total":700}]
The function should be in the InvoiceViewController. How do I get the result?
JSON object you are getting from http://ex.com/app/api/clientList/get should be an array and parameter keys should be same as property name of ClientsList.
struct ClientsList: Decodable {
let name: String
let vatNumber: String
let address: String
let cap: String
let city: String
let prov: String
let tel: String
let email: String
}
If you are not sure that you will receive all properties in the response JSON, then make that particular property optional. like:
struct ClientsList: Decodable {
let name: String
let vatNumber: String
let address: String
let cap: String
let city: String? // Not sure about receiving this property
let prov: String? // Not sure about receiving this property
let tel: String? // Not sure about receiving this property
let email: String
}
Same pattern you need to follow for http://ex.com/app/api/invoiceList/get and InvoiceList.
Related
Trying to grab the below JSON data. I can pull the everything but the foodNutrients. When running the below coded, I receive the following
Result:
MealJournal.FoodNutrients(foodNutrients: nil)
{
"fdcId":748967,
"description":"Eggs, Grade A, Large, egg whole",
"publicationDate":"12/16/2019",
"foodNutrients":[
{
"type":"FoodNutrient",
"nutrient":{
"id":1091,
"number":"305",
"name":"Phosphorus, P",
"rank":5600,
"unitName":"mg"
},
How would I go about grabbing foodNutrients?
I have the below code and I am getting the following results
Code:
struct FoodNutrients: Codable{
let foodNutrients: [String]?
enum CodingKeys: String, CodingKey{
case foodNutrients = "foodNutrients"
}
}
struct Food: Codable{
let dataType: String
let description: String
let fdcId: Int
let foodNutrients: [FoodNutrients]
}
class FoodApi {
func getFood (){
guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/food/748967?api_key=bRbzV0uKJyenEtd1GMgJJNh4BzGWtDvDZVOy8cqG") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
let results = try! JSONDecoder().decode(Food.self, from: data!)
print(results)
}
.resume()
}
}
The food nutrients struct is wrong and needs to match the json. Use https://app.quicktype.io/ to generate the proper classes/structs
I study SwiftUI and I have an interesting task.
I need to get data from a site and store it in CoreData. Then, I need to get them from CoreData and show it in my View if I don't have internet.
I created my data model:
struct User: Codable, Identifiable, Hashable {
struct Friend: Codable, Identifiable, Hashable {
let id: String
let name: String
}
let id: String
let name: String
let isActive: Bool
let age: Int
let company: String
let email: String
let address: String
let about: String
let registered: Date
let friends: [Friend]
}
This is how I get the data form the site:
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
//#FetchRequest(entity: CDUser.entity(), sortDescriptors: []) var users: FetchedResults<CDUser>
#State private var users = [User]()
// some code
// .............
func loadData() {
guard let url = URL(string: "https://****************.json") else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let decoded = try decoder.decode([User].self, from: data)
DispatchQueue.main.async {
self.users = decoded
return
}
} catch {
print("Decode error:", error)
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}
So now I don't know how to store a variable which will contains data from the site and from CoreData when it needed.
Can anyone give some advice?
User entity
Friend entity
I am able to parse JSON using JSONSerialization, but unable to parse with Codable.
the json look like this:
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
}
Please help me with the code.
able to parse using JSONSerialization: data coming
Unable to parse JSON with Codable: data not coming
struct jsonDataModel: Codable{
var name: String
var userName: String
var email: String
init(name: String, username: String, email: String){
self.name = name
self.userName = username
self.email = email
}
}
class WebviewViewController: UIViewController, WKNavigationDelegate {
#IBOutlet weak var testWebView: WKWebView!
//var itemsArray = [jsonDataModel]()
override func viewDidLoad() {
super.viewDidLoad()
serviceCall()
}
func serviceCall()
{
let jsonString = "https://jsonplaceholder.typicode.com/users"
let jsonData = jsonString.data(using: .utf8)!
do {
let jsonDecoder = JSONDecoder()
let user = try jsonDecoder.decode(jsonDataModel.self, from: jsonData)
print("all data \(user)")
print("Hello \(user.name), \(user.userName), \(user.email) ")
} catch {
print("Unexpected error: \(error).")
}
}
}
Please help me to parse json with codable.
Try this example.
import UIKit
import Foundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
do{
let jsonDataModels = try JSONDecoder().decode([JSONDataModel].self, from: data)
print(String(data: data, encoding: .utf8)!)
print("jsonDataModels: \(jsonDataModels)")
}catch{}
}
task.resume()
}
}
struct JSONDataModel: Codable {
let id: Int
let name, username, email: String
let address: Address
let phone, website: String
let company: Company
}
struct Address: Codable {
let street, suite, city, zipcode: String
let geo: Geo
}
struct Geo: Codable {
let lat, lng: String
}
struct Company: Codable {
let name, catchPhrase, bs: String
}
First of all, if you're using a URL, then to get data you need to use a networking api. URLSession is the iOS provided api to perform network operations like download/upload.
So, just using Codable doesn't make any sense. You need to first have the data in order to parse it with Codable.
Here is the model,
struct Model: Codable {
let id: Int
let name, username, email: String
}
And you can use it in your controller's viewDidLoad() method,
if let url = URL(string: "https://jsonplaceholder.typicode.com/users") {
URLSession.shared.dataTask(with: url) { (data, urlResponse, error) in
if let data = data {
do {
let response = try JSONDecoder().decode([Model].self, from: data)
print(response.map({ $0.name })) //prints all the names
} catch {
print(error)
}
}
}.resume()
}
I am trying to access a url string contained within some JSON data.
The string is contained within the "urls" array with type "detail" as can be seen below.
JSON DATA
I used quicktype to construct my model as below:
struct Response: Codable {
let data: DataClass
}
struct DataClass: Codable {
let results: [Result]
}
struct Result: Codable {
let name: String
let description: String
let thumbnail: Thumbnail
let urls: [URLElement]
}
struct Thumbnail: Codable {
let path: String
let thumbnailExtension: Extension
enum CodingKeys: String, CodingKey {
case path
case thumbnailExtension = "extension"
}
}
enum Extension: String, Codable {
case jpg = "jpg"
}
struct URLElement: Codable {
let type: URLType
let url: String
}
enum URLType: String, Codable {
case comiclink = "comiclink"
case detail = "detail"
case wiki = "wiki"
}
I have tried accessing it by declaring it like so...
var urlelement: URLElement!
override func viewDidLoad() {
super.viewDidLoad()
let detailurl = urlelement.url
print(detailurl)
... but it always returns an empty string. Any suggestions will be most welcome. Thanks!
First Download the JSON then user JSONDecoder
let url = URL(string: "your url")!
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("error \(error.localizedDescription)")
return
}
guard let data = data else { return }
do {
let response = try JSONDecoder().decode(Response.self, from: data)
// use this
response?.data.results.forEach({ (rsl) in
rsl.urls.forEach({ (element) in
print(element.type, element.url)
})
})
// or this one
for rsl in response!.data.results {
for element in rsl.urls {
print(element.type, element.url)
}
}
} catch let error {
print("error while decoding the json \(error.localizedDescription)")
}
}.resume()
I hava a json file:
jsonpElixo({
"response":{
"parks":[
{
"Park":{
"id":"2",
"name":"PARQUE VILLA-LOBOS",
"type":"Urbano"
},
"Address":{
"lat":"-23.547245206920508",
"long":"-46.71627699999999",
"cep":null,
"street":"Avenida Professor Fonseca Rodrigues",
"number":"1025",
"neighborhood":"Alto Pinheiros",
"city":"S\u00e3o Paulo",
"state":"SP",
"id":"9"
}
}
]
}
})
But I can't get the elements inside the {}. Because the "jsonpElixo(" is breaking during the decodable.
How can I fix that?
The func to get info about json file.
func getParks() {
var request = URLRequest(url:gitUrl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let welcome = try? decoder.decode(Welcome.self, from: data)
} catch let err {
print("Err", err)
}
}.resume()
}
The structs to Decodable the elements. But I dont know how can I scape this first element ("jsonpElixo(")
struct Welcome: Decodable {
let response: Response
}
struct Response: Decodable {
let parks: [Park]
}
struct Park: Decodable {
let park: ParkClass
let address: Address
enum CodingKeys: String, CodingKey {
case park = "Park"
case address = "Address"
}
}
struct Address: Decodable {
let lat, long: String
let cep: String?
let street, number, neighborhood, city: String
let state, id: String
}
struct ParkClass: Decodable {
let id, name, type: String
}
You can create a function that will remove the outer jsonpElixo() object and return the json to work with.
Start with an extension on Data so we can create something similar to this:
extension Data {
func decodeJsonpElixo() -> Data {
guard let jsonpString = String(data: self, encoding: .utf8) else {return self}
if jsonpString.hasPrefix("jsonpElixo(") && jsonpString.hasSuffix(")") {
var decoderString = jsonpString.replacingOccurrences(of: "jsonpElixo(", with: "")
decoderString.remove(at: String.Index(encodedOffset: decoderString.endIndex.encodedOffset - 1))
return Data(decoderString.utf8)
}
return self
}
}
Then you can use this in your URLSession closure like this:
guard let data = data else { return }
let decoderData = data.decodeJsonpElixo()
let decoder = JSONDecoder()
do {
let welcome = try decoder.decode(Welcome.self, from: decoderData)
} catch let err {
print(err)
}