parsing Json in swift4 - json

hello i try to decode Json:
{"result":[
{"ID":"80",
"time":"09:00:00",
"status":[
{"status":0,"kirpeja_id":"74","name":"Natalja","image":"natalija255.png","duration":"00:20:00"},
{"status":1,"kirpeja_id":"80","name":"Lina","image":"kazkas.png","duration":"00:30:00"},
{"status":0,"kirpeja_id":"82","name":"Rasa ","image":"IMG_20170906_171553.jpg","duration":"00:40:00"}
]},
{"ID":"81",
"time":"09:10:00",
"status":[
{"status":0,"kirpeja_id":"66","name":"Ilona","image":"ilona_new.jpg","duration":"00:30:00"},
{"status":0,"kirpeja_id":"74","name":"Natalja","image":"natalija255.png","duration":"00:20:00"},
{"status":0,"kirpeja_id":"80","name":"Lina","image":"kazkas.png","duration":"00:30:00"},
{"status":0,"kirpeja_id":"82","name":"Rasa ","image":"IMG_20170906_171553.jpg","duration":"00:40:00"}
]},
...
here my classes
class TimeStatusResult: Codable {
let result: [TimeStatus]
init (result:[TimeStatus]) {
self.result = result
}
}
class TimeStatus: Codable {
let ID:String?
let time: String?
let status: [Status]
init (status:[Status]) {
self.ID = ""
self.time = ""
self.status = status
}
}
class Status: Codable {
let status: String?
let kirpeja_id: String?
let name: String?
let image: String?
let duration: String?
init () {
self.status = ""
self.kirpeja_id = ""
self.name = ""
self.image = "nophoto.jpg"
self.duration = ""
}
}
here my json function
final let jsonUrl = URL(string: "http://**********/getlaikas_new.php")
private var timeStatusResult = [TimeStatus]()
func downloadJson () {
guard let downloadURL = jsonUrl else {return}
var request = URLRequest(url: downloadURL)
request.setValue("application/x-www-form-urlencoded",forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "data=\(pInfo.paslaugosData!)&salonId=\(pInfo.ID!)&paslaugos_id=\(pInfo.paslaugosId!)"
request.httpBody = postString.data(using: .utf8, allowLossyConversion: true)
URLSession.shared.dataTask(with: request) {data, urlResponse, error in
guard let data = data , error == nil, urlResponse != nil else {
print ("something wrong")
return }
print ("downloaded!")
do
{
let decoder = JSONDecoder()
print (data)
let downloadedTimeStatus = try decoder.decode(TimeStatusResult.self, from: data)
self.timeStatusResult = downloadedTimeStatus.result
DispatchQueue.main.async {
// self.kirpejosPaslaugosTable.reloadData()
}
} catch {
print ("something wrong after download")
}
}.resume()
}
in this line i have issue
let downloadedTimeStatus = try decoder.decode(TimeStatusResult.self, from: data)
somebody can help me? :(

The error is very clear:
...burzua_1.Status.(CodingKeys in _479ABD1AF7892C9F2FD23EC23214E088).status], debugDescription: "Expected to decode String but found a number instead."
The value for key status is not in double quotes so it's an Int
class Status: Codable {
let status: Int
...
Please don't declare all properties carelessly as optional. For example status as well as all other keys is present in all Status dictionaries.

Related

SwiftUI Display JSON Data after GET Request

I know this is classic concurrency problem, but I'm new to Swift and I feel like I've read through every relevant blog post about this. I know I'm fetching data correctly because it's showing up in my console, but I can't get it to display in my simulator. I believe it's because I'm displaying the UI before the data has loaded.
How can I display the data after I 100% fetched all the data. I'll add the relevant code and screenshots of the console. Sorry if this is a "basic" question.
Structs
struct Welcome: Decodable, Identifiable {
var id: Int?
var readings: [Reading]?
var include_maintenance_recommendations: Bool?
var pool_volume: Int?
var created_at, updated_at: String?
}
struct Reading: Decodable {
var analyte: String?
var value: String?
}
UI
var results = Welcome()
struct ContentView: View {
#State var res = Welcome()
var body: some View {
Text(results.created_at ?? "N/A")
.onAppear(){
fetchResults().getData {(res) in
self.res = res
}
}
}
}
Fetch Func
class fetchResults{
func getData(completion: #escaping (Welcome) -> ()){
print("Fetch")
let parameters = "{ \"pool_volume\": 10000, \"readings\": [ { \"analyte\": \"fc\", \"value\": 1.6 }, { \"analyte\": \"ph\", \"value\": 7.3 } ]}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://www.biolabhydra.com/api/v3/water_tests")!,timeoutInterval: Double.infinity)
request.addValue("Basic ***********************", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("csrftoken=***********************", forHTTPHeaderField: "Cookie")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { (data, _, _) in
let resultList = try! JSONDecoder().decode(Welcome.self, from: data!)
print(" ")
print("ID: \(resultList.id ?? 111)")
print("VOLUME: \(resultList.pool_volume ?? 111)")
print("RECOMMENDATIONS: \(resultList.include_maintenance_recommendations ?? true)")
print("CREATD AT: \(resultList.created_at ?? "N/A")")
print("UPDATED AT: \(resultList.updated_at ?? "N/A")")
print("READINGS: \(String(describing: resultList.readings))")
print(" ")
print("SUCCESS: Got data - \(data! )")
}
task.resume()
}
}
Use local property instead of global variable
struct ContentView: View {
#State var res = Welcome()
var body: some View {
Text(res.created_at ?? "N/A") // << here !!
.onAppear(){
fetchResults().getData {(res) in
self.res = res
}
}
}
}
add callback after decoded data
let task = URLSession.shared.dataTask(with: request) { (data, _, _) in
let result = try! JSONDecoder().decode(Welcome.self, from: data!)
print(" ")
print("ID: \(resultList.id ?? 111)")
print("VOLUME: \(resultList.pool_volume ?? 111)")
print("RECOMMENDATIONS: \(resultList.include_maintenance_recommendations ?? true)")
print("CREATD AT: \(resultList.created_at ?? "N/A")")
print("UPDATED AT: \(resultList.updated_at ?? "N/A")")
print("READINGS: \(String(describing: resultList.readings))")
print(" ")
print("SUCCESS: Got data - \(data! )")
DispatchQueue.main.async {
completion(result) // << here !!
}
}

How to pass two values in URL body in JSON swift?

I am trying to add parameters in URL body like below
func getUserProfile() {
let deviceId: String = "HardcodeDEVICEIDforiTaag"//(UIDevice.current.identifierForVendor?.uuidString)!
let personalId: String = UserDefaults.standard.string(forKey: "USERID") ?? ""
let headers = ["deviceid": deviceId,"userType": "personal","key": personalId]
let string = "http://itaag-env-1.ap-south-1.elasticbeanstalk.com/getprofile/"
var urlComponents = URLComponents(string: string)
let requestedUserType = URLQueryItem(name: "requestedUserType", value: "personal")
let requestedItem = URLQueryItem(name: "requestedKey", value: personalId)
urlComponents?.queryItems = [requestedItem, requestedUserType]
let urlStr = urlComponents?.url
print(urlStr?.absoluteString)
let request = NSMutableURLRequest(url: NSURL(string:urlStr)! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers as! [String : String]
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if error == nil {
let httpResponse = response as? HTTPURLResponse
if httpResponse!.statusCode == 200 {
do {
let jsonObject = try JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as! [String :AnyObject]
self.userModel = ProfileModel.init(fromDictionary: jsonObject)
print("profile json \(jsonObject)")
print("profile personalid 2222\(personalId)")
if (self.userModel?.userId) != nil {
DispatchQueue.main.async {
self.updateUserDetails()
self.addressTableview.reloadData()
}
} else { DispatchQueue.main.async { Constants.showAlertView(alertViewTitle: "", Message: "No user data found", on: self)}}
} catch { print(error.localizedDescription) }
} else {
//Constants.showAlertView(alertViewTitle: "", Message: "Something went wrong, Please try again", on: self)
}
}
})
dataTask.resume()
}
then got error:
Cannot convert value of type 'URL?' to expected argument type 'String'
i got above error when i am trying to add url to request.
Please help me to solve this error.
This how one should create a url with different components:
let string = "http://itaag-env-1-south-1.elasticbeanstalk.com/getprofile"
var urlComponents = URLComponents(string: string)
let requestedItem = URLQueryItem(name: "requestedKey", value: "yourReqKey")
let requestedUserType = URLQueryItem(name: "requestedUserType", value: "personal")
urlComponents?.queryItems = [requestedItem, requestedUserType]
let url = urlComponents?.url
print(url?.absoluteString)
Edit: Finally use this code to get your request :-
let request = NSMutableURLRequest(url: url!, cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)

Networking using JSONDecoder & codable protocol

I am wondering what i am doing wrong . I am trying to understand how to use urlsession and codable protocol using JSONDecoder. When i use JSONDecoder i am getting the following error message :
keyNotFound(CodingKeys(stringValue: "name", intValue: nil), my resaponse contain ''name'' . But when i use JSONSerialization, I am able to print the response . If someone can explain me.
Code using JSONDecoder
struct Business:Codable {
let name: String
enum CodingKeys: String, CodingKey {
case name = "name"
}
init(from decoder: Decoder) throws {
let value = try decoder.container(keyedBy: CodingKeys.self)
self.name = try value.decode(String.self, forKey:CodingKeys.name)
}
}
let task = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
print(response)
} else{
print("error")
}
guard let data = data else {return}
do {
let business = try JSONDecoder().decode(Business.self, from: data)
print(business.name)
} catch {
print("Error parsing JSON: \(error)")
}
}
task.resume()
Code using JSONSerialization
struct Business: Decodable {
let name: String
let displayAddress: String
let categories: String
let imageUrl : String
init(json: [String:Any]) {
name = json["name"] as? String ?? ""
displayAddress = json["location"] as? String ?? ""
categories = json["categories"] as? String ?? ""
imageUrl = json["image_url"] as? String ?? ""
}
}
let task = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
print(response)
} else{
print("error")
}
guard let data = data else {return}
do {
if let myjson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? Dictionary<String,Any> {
print(myjson)
}
} catch {
print("Error parsing ")
}
}
task.resume()
The response
["region": {
center = {
latitude = "43.67428196976998";
longitude = "-79.39682006835938";
};
}, "businesses": <__NSArrayM 0x60000211cff0>(
{
alias = "pai-northern-thai-kitchen-toronto-5";
categories = (
{
alias = thai;
title = Thai;
}
);
coordinates = {
latitude = "43.647866";
longitude = "-79.38864150000001";
};
"display_phone" = "+1 416-901-4724";
distance = "3010.095870925626";
id = "r_BrIgzYcwo1NAuG9dLbpg";
"image_url" = "https://s3-media3.fl.yelpcdn.com/bphoto/t-g4d_vCAgZH_6pCqjaYWQ/o.jpg";
"is_closed" = 0;
location = {
address1 = "18 Duncan Street";
address2 = "";
address3 = "";
city = Toronto;
country = CA;
"display_address" = (
"18 Duncan Street",
"Toronto, ON M5H 3G8",
Canada
);
state = ON;
"zip_code" = "M5H 3G8";
};
name = "Pai Northern Thai Kitchen";
phone = "+14169014724";
price = "$$";
rating = "4.5";
"review_count" = 2405;
transactions = (
);
url = "https://www.yelp.com/biz/pai-northern-thai-kitchen-toronto-5?adjust_creative=A4ydpSOHv8wBNquTDeh0DQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=A4ydpSOHv8wBNquTDeh0DQ";
},
Business is not the root data object in your JSON. You need something like this:
struct Business: Codable {
let name: String
}
struct RootObject: Codable {
let businesses: [Business]
}
let rootObject = try JSONDecoder().decode(RootObject.self, from: data)
print(rootObject.businesses.first?.name)

i am trying to parse json with swift 4, please tell me what is wrong in it?

I am trying to parse JSON using the following method, but XCode is giving me an error where I have declared "data" .
I am new, I don't understand what is wrong. Please help me.
import UIKit
struct Contacts: Decodable {
let id: Int
let name: String
let email: String
}
class ViewController: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
let urlString = "https://api.androidhive.info/contacts/"
guard let url = URL(string: urlString) else {return}
URLSession.shared.dataTask(with: url) { (data, response, error) in
}
guard let data = data else {return}
//let datastring = String(data: data, encoding: .utf8)
do
{
let contact = try JSONDecoder().decode([Contacts].self, from: data)
print(contact.name)
} catch let jsonErr {
print("Error deserializing json:", jsonErr)
}
}
}
Three major issues.
You are ignoring the root object which is a dictionary containing the contacts array.
The value for key id is String, not Int.
A hard rule is : Everything in double quotes is String even "12" and "false"
You have to resume the task and put the code to parse the JSON into the completion handler.
struct Root : Decodable {
let contacts : [Contact]
}
struct Contact : Decodable { // It's recommended to name this kind of struct in singular form
let id, name, email: String
}
...
override func viewDidLoad()
{
super.viewDidLoad()
let urlString = "https://api.androidhive.info/contacts/"
guard let url = URL(string: urlString) else {return}
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error { print(error); return }
do {
let result = try JSONDecoder().decode(Root.self, from: data!)
let contacts = result.contacts
for contact in contacts {
print(contact.name)
}
} catch {
print("Error deserializing json:", error)
}
}.resume()
}
//
// ViewController.swift
// PostMethodTest
//
// Created by HABIB UR REHMAN on 12/11/2018.
// Copyright © 2018 HABIB UR REHMAN. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
struct Resturant: Decodable {
var name: String
var deliveryCharges: String
var email: String
init(_ dictionary: [String: Any]) {
self.name = dictionary["name"] as? String ?? ""
self.deliveryCharges = dictionary["deliveryCharges"] as? String ?? ""
self.email = dictionary["email"] as? String ?? ""
}
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "your Link Here ") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) {(data, response, error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do{
//here dataResponse received from a network request
let jsonResponse = try JSONSerialization.jsonObject(with:
dataResponse, options: [])
print(jsonResponse) //Response result
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
}
Please Try this its working for me.
func getContactListsApiCalling() {
var request = URLRequest(url: URL(string: "https://api.androidhive.info/contacts/")!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
if let Data = data {
let responseJSON = try JSONSerialization.jsonObject(with: Data) as? Dictionary<String, AnyObject> ?? [:]
if let contacts = responseJSON["contacts"] as? [[String :AnyObject]] {
for contact in contacts {
let id = contact["id"] as? String ?? ""
let name = contact["name"] as? String ?? ""
let email = contact["email"] as? String ?? ""
let address = contact["address"] as? String ?? ""
let gender = contact["gender"] as? String ?? ""
print(id,name,email,address,gender)
}
}
}
} catch {
print("error")
}
})
task.resume()
}
}

Json parse array in dictionary

I use json api in my application. It can check a company does use electronic Invoice. I have a json data like that:
{
"ErrorStatus": null,
"Result": {
"CustomerList": [
{
"RegisterNumber": "6320036072",
"Title": "VATAN BİLGİSAYAR SANAYİ VE TİCARET ANONİM ŞİRKETİ",
"Alias": "urn:mail:defaultpk#vatanbilgisayar.com",
"Type": "Özel",
"FirstCreationTime": "2014-01-01T05:35:20",
"AliasCreationTime": "2014-01-01T05:35:20"
}
],
"ISEInvoiceCustomer": true
} }
and i use that fucntion for get json data:
func getClientQuery(authorization:String) {
let url = NSURL(string: URLCustomerCheck+strRegisterNumber)
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "GET"
request.addValue(authorization, forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request as URLRequest) { data,response,error in
if error != nil {
let alert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
let okButton = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alert.addAction(okButton)
self.present(alert, animated: true, completion: nil)
} else {
if data != nil {
do {
let jSONResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,AnyObject>
DispatchQueue.main.async {
print(jSONResult)
let result = jSONResult["Result"] as! [String:AnyObject]
//let customerList = result["CustomerList"] as! [[String:AnyObject]]
let ISEInvoiceCustomer = String(describing: result["ISEInvoiceCustomer"])
self._lblISEinvoiceCustomer.text = " \(ISEInvoiceCustomer) "
}
} catch {
}
}
}
}
task.resume()
}
My question is how can i parse "RegisterNumber", "Title".. in "CustomerList"? It's a array that have a member. However i can not parse it in my function.
The customerList line you commented out is needed. Then iterate that array and pull out whatever values you want from each dictionary.
And you really should avoid us as! or any other forced unwrapping when working with JSON. You don't want your app to crash when you obtain unexpected data.
And never use String(describing:) to create a value you will display to a user. The result is inappropriate for display. It's only to be used for debugging purposes.
if let jSONResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String:Any]
DispatchQueue.main.async {
print(jSONResult)
if let result = jSONResult["Result"] as? [String:AnyObject],
let customerList = result["CustomerList"] as? [[String:Any]] {
for customer in customList {
let registrationNumber = customer["RegisterNumber"]
// and any others you need
}
let ISEInvoiceCustomer = result["ISEInvoiceCustomer"] as? Bool ?? false
self._lblISEinvoiceCustomer.text = ISEInvoiceCustomer) ? "Yes" : "No"
}
}
}
Better to Map json to Model , this become easy using Codable
import Foundation
struct Client: Codable {
let errorStatus: ErrorStatus?
let result: Result
enum CodingKeys: String, CodingKey {
case errorStatus = "ErrorStatus"
case result = "Result"
}
}
struct ErrorStatus: Codable {
}
struct Result: Codable {
let customerList: [CustomerList]
let iseInvoiceCustomer: Bool
enum CodingKeys: String, CodingKey {
case customerList = "CustomerList"
case iseInvoiceCustomer = "ISEInvoiceCustomer"
}
}
struct CustomerList: Codable {
let registerNumber, title, alias, type: String
let firstCreationTime, aliasCreationTime: String
enum CodingKeys: String, CodingKey {
case registerNumber = "RegisterNumber"
case title = "Title"
case alias = "Alias"
case type = "Type"
case firstCreationTime = "FirstCreationTime"
case aliasCreationTime = "AliasCreationTime"
}
}
// MARK: Convenience initializers
extension Client {
init(data: Data) throws {
self = try JSONDecoder().decode(Client.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
}
Get customerList :
func getClientQuery(authorization:String) {
let url = NSURL(string: URLCustomerCheck+strRegisterNumber)
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "GET"
request.addValue(authorization, forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request as URLRequest) { data,response,error in
if error != nil {
let alert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
let okButton = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alert.addAction(okButton)
self.present(alert, animated: true, completion: nil)
} else {
if data != nil {
if let client = try? Client.init(data: data){
client.result.customerList.forEach { (customer) in
print(customer.registerNumber)
}
}
}
}
}
task.resume()
}
let data = resultData
do {
guard let JSONResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String : AnyObject],
let resultObject = JSONResult["Result"] as? [String : AnyObject],
let customerList = resultObject["CustomerList"] as? [Anyobject]
else { return }
// Loop the array of objects
for object in customerList {
let registerNumber = object["RegisterNumber"] as? String
let title = object["Title"] as? String
let alias = object["Alias"] as? String
let type = object["Type"] as? String
let firstCreationTime = object["FirstCreationTime"] as? String // Or as a DateObject
let aliasCreationTime = object["AliasCreationTime"] as? String // Or as a DateObject
}
let isEInvoiceCustomer = resultObject["ISEInvoiceCustomer"] as? Bool
} catch {
print(error)
}