How to add parameters to JSON in function in swift - json

I have created one function for JSON parsing, which I am calling in every view controller, but i am unable to pass parameters from that function
i have created function in NSObject class:
func serviceCall(_ url: String, _ params:[String : Any], completion: #escaping (Data?, Error?) -> Void) {
let url = URL(string: url)!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST" //set http method as POST
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
URLSession.shared.dataTask(with: urlRequest) { data, response, error in
if let error = error {
completion(nil, error)
return
}
guard let data = data else {
preconditionFailure("No error was received but we also don't have data...")
}
completion(data, nil)
}.resume()
}
}
in registrationVC how to add parameters to this function
my parameters for registration service:
struct RegData: Codable {
var jsonrpc: String
var params: PostReg
}
struct PostReg: Codable{
var email: String
var password: String
var device_id: String
}
while calling serviceCall function how to add parameters to it
if i call like this in button action
let url = "https://e/api/reg"
let jsonpostParameters: [String: Any] = RegData(jsonrpc: "2.0", params: (PostLogin(email: nameTf.text!, password: passwordTf.text!, device_id: "2")))
self.fetch(url, jsonpostParameters) { (data: Data?, error: Error?) in
guard let dt = data else { return }
// convert data to JSON
print(dt)
error:
cannot convert a value [String:Any] to RegData
how to add RegData to serviceCall, shall i change serviceCall params type? if yes how..
how add RegData to serviceCall to parse JSON

Kindly try this for decode data
//Here ResponceData is your codable class
let dictData = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
let obj= try JSONDecoder().decode([ResponseData].self, from: dictData)

Related

SwiftUI URLSession JSONDecoder returning error when trying to parse nested Json

I am trying to parse a nested Json in SwiftUI for the last couple of days and I have no idea how to move forward.
At this point, I suspect that the trouble is a parameter received within the Json named "data" which might cause a confusion between the param value in struct "VTResponse" and the data param that URLSession.shared.dataTask is getting.
Here's the code at this point:
import UIKit
struct VTResponse: Decodable {
let data: [VT]
}
struct VT: Decodable {
var id: String
}
let token = "<TOKEN>"
let XDOMAIN = "<XDOMAIN>"
guard let url = URL(string: "https://www.lalalla.com/subdomains") else {
fatalError("Invalid URL")
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("x-apikey: \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { return }
let result = try? JSONDecoder().decode(VTResponse.self, from: data)
if let result = result {
result.data.forEach {
print($0.id)
}
}
else {
print("Error")
}
}.resume()
Assuming that I define a token and domain for the query, for example, lookup all of the subdomains of "giphy.com", the Json response:
Json Response - Pastebin
As you can see in the Json response, the subdomains parameter ("id") is under a dictionary, under an array("data"). My guess is the code is trying to assign data to the variable:
guard let data = data, error == nil else { return }
But this is just a guess. And even if so, how could I solve this?
Anyways, I'm getting the following output:
Error
I'm trying to get the following output:
pingback.giphy.com
media3.giphy.com
api.giphy.com
developers.giphy.com
media.giphy.com
x-qa.giphy.com
media1.giphy.com
x.giphy.com
media4.giphy.com
media0.giphy.com
Any ideas?
try this using an x-apikey header for your token:
func fetchData(token: String, XDOMAIN: String, completion: #escaping (VTResponse) -> Void) {
guard let url = URL(string: "https://www.virustotal.com/api/v3/domains/\(XDOMAIN)/subdomains") else {
fatalError("Invalid URL")
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("\(token)", forHTTPHeaderField: "x-apikey") // <-- here
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return } // todo return some error msg
do {
let results = try JSONDecoder().decode(VTResponse.self, from: data)
return completion(results)
} catch {
print(error) // <-- here important
}
}.resume()
}
And use it like this:
fetchData(token: "xxx", XDOMAIN: "www") { results in
results.data.forEach {
print("---> id: \($0.id)")
}
}
EDIT-1: to get an array of [String], that is, of id, use this function:
func ListFromSubDomains(token: String, XDOMAIN: String, completion: #escaping ([String]) -> Void) {
fetchData(token: token, XDOMAIN: XDOMAIN) { results in
completion(results.data.map{ $0.id })
}
}
and use it like this:
var IPList: [String] = []
ListFromSubDomains(token: "xxx", XDOMAIN: "www") { ids in
IPList = ids
print("---> ids: \(ids)")
}

How else can I format the data? swift parse json - The data couldn’t be read because it isn’t in the correct format

The JSON data is
[
{"id":0,"temperature":77,"humidity":0.22,"timeCaptured":"2020-09-25T19:33:27.9733333"},
{"id":0,"temperature":77,"humidity":0.22,"timeCaptured":"2020-09-25T20:38:53.3"},
{"id":0,"temperature":85,"humidity":0.25,"timeCaptured":"2020-09-25T20:38:53.3"},
{"id":0,"temperature":88,"humidity":0.22,"timeCaptured":"2020-09-28T15:30:00"},
// ...
]
My structs look like this
struct TemperatureDataModel: Codable{
let id: Int?
let temperature: Double?
let humidty: Double?
let timeCaptured: String?
}
My function looks like this
func getTemperData(){
//Create the URLs
let temperatureDataUrl = URL(string: "https://weatherstationapi.azurewebsites.net/api/TemperatureSensor/GetData")
// let WindDataUrl = URL(string: "https://weatherstationapi.azurewebsites.net/api/WindData/GetAllData")
guard let requestURLTemp = temperatureDataUrl else { fatalError() }
//Create URL request
var request = URLRequest(url: requestURLTemp)
//Specifiy HTTP Method to use
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiaWxpci50YWlyaUB0dHUuZWR1IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiI4MjEzYzhhMy1iODgxLTQ4NmUtOGUyMC1mZmNlMDlmNGY0ZjgiLCJuYmYiOiIxNjAyNTI2NDI1IiwiZXhwIjoiMTYwNTExODQyNSJ9.t1qnYyXLpRRJ3YQfhgLrylBqL_pdKOnKVMgOfG9IuVc", forHTTPHeaderField: "Authorization")
//Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else {return}
print(data)
//Use parseJSON to convert data
let TemperatureData = parseJSON(data: data)
// for singleValue in TemperatureData {
// print(singleValue.temperautre)
// }
//read list
guard let TemperatureDataModel = TemperatureData else {return}
print("Temperature is : \(TemperatureDataModel.temperature)")
// Check if error took place
if let error = error {
print("Error took place \(error)")
return
}
//Read HTTP Response Status Code
// if let data = data, let dataString = String(data: data, encoding: .utf8) {
// print("Response data string:\n \(dataString)")
// }
}
task.resume()
}
and then my JSON decoder function looks like this
func parseJSON(data: Data) -> TemperatureDataModel? {
var returnValue: TemperatureDataModel?
do {
let returnValue = try JSONDecoder().decode([TemperatureDataModel].self, from: data)
} catch {
print("Error took place \(error).")
}
return returnValue
}
I've looked at 6+ stack overflow posts now and still cannot figure It out. Ive tried putting my model in [] for an array, moving where the function is called, changing the jsondecoder function and more and nothing works.
I think you have to give a format to the date before you parse the data
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
Your issue there is that you are creating another returnValue that is not being returned. You need also change the return type to [TemperatureDataModel]
func parseJSON(data: Data) -> [TemperatureDataModel]? {
do {
return try JSONDecoder().decode([TemperatureDataModel].self, from: data)
} catch {
print("Error took place \(error).")
return nil
}
}

JSON Parsing sometimes crashes Swift

I am parsing JSON in my iOS app and sometimes when the network connection is weak but isn’t gone, the app will crash while trying to parse the JSON, because it says it had an error while force unwrapping a nil.
The code I use for that is here.
//
// MessageModel.swift
// truthordare
//
// Created by Dustin Palmatier on 11/2/19.
// Copyright © 2019 Hexham Network. All rights reserved.
//
import UIKit
protocol MessageModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class MessageModel: NSObject, URLSessionDataDelegate {
//properties
weak var delegate: MessageModelProtocol!
let urlPath = "Redacted" //this will be changed to the path where service.php lives
let deleteUrl = "REDACTED"
func downloadItems(TYPE: String, IDENTIFIER: String) {
let url: URL = URL(string: urlPath)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = "type=\(TYPE)&identifier=\(IDENTIFIER)";
request.httpBody = postString.data(using: String.Encoding.utf8);
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func deleteItems(TYPE: String, SKU: String) {
let myUrl = URL(string: "https://truthordare.hexhamnetwork.com/api/92fFDd93D/erase.php");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
let postString = "type=\(TYPE)&sku=\(SKU)";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(error ?? "Empty" as! Error)")
return
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: [.allowFragments, .mutableContainers]) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let tables = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let table = TableModel()
//the following insures none of the JsonElement values are nil through optional binding
if let sku = jsonElement["SKU"] as? String,
let message = jsonElement["MESSAGE"] as? String
{
table.sku = sku
table.message = message
}
tables.add(table)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: tables)
})
}
}
It crashes once it gets to
self.delegate.itemsDownloaded(items: tables)
It says that it received a nil while force unwrapping
To initialize the delegate I called this within the classes that were calling this.
messageModel.delegate = self
To avoid the crash reliably declare delegate as regular optional
weak var delegate: MessageModelProtocol?
and call it
self.delegate?.itemsDownloaded(items: tables)
In Swift 4+ it's highly recommended to use the Codable protocol and in any Swift version a completion handler rather than protocol / delegate.
And don't use NS... collection types in Swift at all. Use native types. And .mutableContainers / .allowFragments is pointless in Swift if the expected type is a collection type. Omit the parameter.

Parsing JSON array without for statement

I want to find a solution for parsing JSON array. there is my code for parsing JSON but I want a solution without for statement I can parse array.
code for parsing:
func parsigJsonData(resultArray:any?){
if let resultArray = resultDic["trucks"] as? BaseModelData {
print(resultArray)
}
}
class BaseModel {
public typealias BaseModelData = (id:String?,title:String?,select:Bool)
var id : String?
var title : String?
var select : Bool = false
init(json: [String:Any]) {
self.id = json["id"] as? String
self.title = json["title"] as? String
self.select = false
}
}
extension BaseModel {
var tableRepresentation: [BaseModelData] {
return [(id:id,title:title,select:select)]
}
}
result array contains list of baseModel object. I try this code for parsing but that's not working and casting to BaseModelData unsuccessful.
if there is a solution for parsing JSON array without for statement?
Thank you for the solutions.
there is my json response sample:
{"trucks":[{"id":"1","title":"\u062e\u0627\u0648\u0631 \u062a\u0627 5 \u062a\u0646 \u0627\u062a\u0627\u0642 \u0686\u0648\u0628\u06cc"},{"id":"2","title":"\u062e\u0627\u0648\u0631 \u062a\u0627 5 \u062a\u0646 \u06a9\u0645\u067e\u0631\u0633\u06cc"},{"id":"3","title":"\u062e\u0627\u0648\u0631 \u062a\u0627 8 \u062a\u0646 \u0627\u062a\u0627\u0642 \u0686\u0648\u0628\u06cc"},{"id":"4","title":"\u062e\u0627\u0648\u0631 \u062a\u0627 8 \u062a\u0646 \u06a9\u0645\u067e\u0631\u0633\u06cc"},{"id":"5","title":"\u062e\u0627\u0648\u0631 \u06cc\u062e\u0686\u0627\u0644 \u062f\u0627\u0631"}]
Swift 4 allows you to make it very simple. Just add Decodable protocol,
struct BaseModel: Codable {
var id : String?
var title : String?
var select : Bool = false
}
And use this to retrieve data:
func makeRequest(completionHandler: #escaping ([BaseModel]?, Error?) -> Void) {
var urlRequest = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request as URLRequest){
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
completionHandler(nil, error)
return
}
guard error == nil else {
completionHandler(nil, error)
return
}
let decoder = JSONDecoder()
do {
let dataObject = try decoder.decode([BaseModel].self, from: responseData)
completionHandler(dataObject, nil)
} catch {
print("error trying to convert data to JSON")
print(error)
completionHandler(nil, error)
}
}
task.resume()
}

Swift 1.2: Unexpected non-void return value in void function

I have written a function which should return a certain value from a page. I have done this with JSON, so that I can get a certain value from my website. This is the function:
func getTimerData() {
var currentUsername = PFUser.currentUser()!.username
let url = NSURL(string: "http://dinges.informatica-dinges.nl/timerDataTransmitter.php?user=\(currentUsername!)&unique=85017438957")
let request = NSMutableURLRequest(URL: url!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
var parseError: NSError?
if let json = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: &parseError) as? [String: String] {
let rideTime = json["timerValue"]
return rideTime
}
}
}
However, it gives me the error: Unexpected non-void return value in void function. I have tried a lot but I can't seem to find a way to fix this problem. Do you know how I can fix it?
Declare your function with return data type as you required
such as :
fun getTimerData() -> String {
var currentUsername = PFUser.currentUser()!.username
let url = NSURL(string: “http://dinges.informatica-dinges.nl/timerDataTransmitter.php?user=\(currentUsername!)&unique=85017438957”)
let request = NSMutableURLRequest(URL: url!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
var parseError: NSError?
if let json = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: &parseError) as? [String: String] {
let rideTime = json["timerValue"]
return rideTime
}
}
}