Currently I able to show full out out from GET method which return json data.
but I am unable to show individual object . i.e values of description or engine . but I can print the whole json data.
my code
let url = URL(string: "https://mylink/last")!
var request = URLRequest(url: url)
request.allHTTPHeaderFields = [
"Content-Type": "application/json",
"Session": "b14549"
]
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print (response)
}
if let data = data {
print (data)
do {
let jsonresult = try JSONSerialization.jsonObject(with: data, options: [])
// This works
print (jsonresult)
// Bellow does not work , Give Error Value of type 'any' has no subscripts
print (jsonresult["device_id"])
print (jsonresult["engine"])
} catch {
print(error)
}
}
}.resume()
}
I looked at other solution , tried bellow not working not sure if its related to the data type I am getting. I have posted the out put of jsonresult bellow.
JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
out put of Json result : -
(
{
"device_id" = "3aff273f-7f5f-49ef-81a6-50e2fcc2f69f”;
engine = 0;
"last_timestamp" = "2019-10-25 17:33:45";
},
{
"device_id" = "44b0ab5f-5289-4c56-b864-ce4899c2fcb8”;
engine = 0;
"last_timestamp" = "2019-10-25 17:33:40";
},
{
"device_id" = "c5639e8b-7f56-4021-9925-828ed735f527";
engine = 0;
}
)
The result is clearly an array, please note the () in the output.
You have to cast the result to the expected type
if let jsonresult = try JSONSerialization.jsonObject(with: data) as? [[String:Any]] {
for item in jsonresult {
print(item["device_id"])
print(item["engine"])
}
}
Related
i have the following Json
USD {
"avg_12h" = "8252.96";
"avg_1h" = "8420.80";
"avg_24h" = "8253.11";
"avg_6h" = "8250.76";
rates = {
last = "8635.50";
};
"volume_btc" = "76.05988903";
}
where USD is a key found after searching in a json file, i want to access "avg_12h" value and assign it to a variable, what is the best way to do it.
import UIKit
/*URLSessionConfiguration.default
URLSessionConfiguration.ephemeral
URLSessionConfiguration.background(withIdentifier: <#T##String#>)
// create a URLSession instance
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)*/
/*create a URLSession instance*/
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
/*
The session.dataTask(with: url) method will perform a GET request to the url specified and its completion block
({ data, response, error in }) will be executed once response is received from the server.*/
let url = URL(string: "https://localbitcoins.com/bitcoinaverage/ticker-all-currencies")!
let task = session.dataTask(with: url) { data, response, error in
// ensure there is no error for this HTTP response
guard error == nil else {
print ("error: \(error!)")
return
}
// ensure there is data returned from this HTTP response
guard let content = data else {
print("No data")
return
}
/*JSONSerialization.jsonObject(with: content,
options: JSONSerialization.ReadingOptions.mutableContainers) as?
[String: Any] will parse the JSON data returned from web server into a dictionary*/
// serialise the data / NSData object into Dictionary [String : Any]
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
print("Not containing JSON")
return
}
let bolivares = "VES"
for (key, value) in json {
if key==bolivares {
print(value)
//ADD CODE TO ACCESS avg_12h and assign it to a value
}
}
}
// update UI using the response here
// execute the HTTP request
task.resume()
Assuming you are receiving the JSON as raw data and it hasn't been converted to an object yet, ou would want to do something like the following:
guard let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) as! [String:[String]] else { return }
let usd = jsonObject["USD"]
let avg_12h = usd["avg_12h"]
But this will only work based on some assumptions I've made about the JSON you've provided. Is there a way you can link to a paste of the full JSON file?
Create two simple structs to hold your data (I didn't add all fields here)
struct PriceInfo {
let avg12h: String
let avg1h: String
let rates: [Rate]
}
struct Rate {
let last: String
}
then after converting json you can map it to a dictionary of [String: PriceInfo] where the key is the currency code
do {
if let json = try JSONSerialization.jsonObject(with: content) as? [String: Any] {
let prices: [String: PriceInfo] = json.mapValues {
let dict = $0 as? [String: Any]
let avg12h = dict?["avg_12h"] as? String ?? ""
let avg1h = dict?["avg_1h"] as? String ?? ""
let rates = dict?["rates"] as? [String: String] ?? [:]
return PriceInfo(avg12h: avg12h, avg1h: avg1h, rates: rates.compactMap { rate in Rate(last: rate.value) } )
}
}
} catch {
print(error)
return
}
Try to use CodingKey, it will be more clearer and JSONDecoder().decode method. I assume that you use any JsonViewer
I build an little task in SWIFT-XCode where I am trying to fetch and print some JSON Data, but the console doesn´t show me any error´s or result. Maybe someone can help me with the problem?. Here´s my code:
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(lat),\(long)&destination=\(lat+auflong),\(long+auflat)&key=**************")
let task = URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if let data = data {
do {
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
task.resume()
If you debug-step through the code, you see the result in the debug area: watch area.
In my test (using incorrect co-ordinates), when I put a breakpoint at the line starting `let jsonSerialized = '..., return 3 dictionary keys:
status
error_message
routes
But you were expecting url and explantion...
If you change the inner like:
let jsonSerialized = ...
if let json = jsonSerialized
{
print(json)
if let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
}
} catch ...
you'll be able to print the returned json. (Replaced some code with ... for easy reading.)
My output:
["status": REQUEST_DENIED, "error_message": The provided API key is invalid., "routes": <__NSArray0 0x600000003910>(
)
]
Let's say I got the following struct
public class Response: Codable {
let status: String
let code: String
let id: String
}
What I want is to get the class properties and values as [String: Any] to send it through Alamofire like this:
let response: Response = Response(status: "A", code: "B", uuid: "C")
let data = try JSONEncoder().encode(res)
//Data to [String : Any]
Alamofire.request("endpoint", method: .post, parameters: params).responseJSON {
// Handle response
}
You can use something like this:
let response: Response = Response(status: "A", code: "B", uuid: "C")
let data = try JSONEncoder().encode(res)
//Data to [String : Any]
do {
let params = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
Alamofire.request("endpoint", method: .post, parameters: params).responseJSON {
// Handle response
}
} catch {
print(error)
}
Try using JSONSerialization as below I had used to get data from JSON
func HitApi(){
Alamofire.request(urlToGetTimeTable, method: .get, parameters: nil , encoding:URLEncoding.default).responseJSON { (response) in
if(response.result.isSuccess)
{
if let JSON = response.result.value
{
print("JSON: \(JSON)")
do {
//Clearing values in Array
self.subjectNameArray.removeAll()
//get data and serialise here to get [String:Any]
if let data = response.data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let dataDict = json["data"] as? [[String: Any]]
{
// iterate an array
for dict in dataDict
{
//get data from JSON Response
let subjectName = dict["subjects_id"] as? String
self.subjectNameArray.append(subjectName!)
}
// TableView Delegate & DataSource
// Reload TableView
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.reloadData()
}
}
catch
{
//Error case
print("Error deserializing JSON: \(error)")
}
}
}
if(response.result.isFailure)
{
//Show Alert here //reason Failure
}
}
}
Give you an idea to get response as [String:Any] using son serialisation , you can use Above format in Post Method need some Modification. I deleted Rest code and showed main Code that was required
I'm trying to write a completion handler function in Swift, here's my code in Swift with a class called NBObject
typealias CompletionHandler = (_ success: Bool, _ data: [String:Any]) -> Void
// FIND OBJECTS IN BACKGROUND
func findObjectInBackground(completionHandler: CompletionHandler) {
let tbNameStr = "table=" + theTableName
var rStr = ""
var theData = [String:Any]()
for i in 0..<columns.count {
rStr += "&c" + "\(i)" + "=" + columns[i] +
"&r" + "\(i)" + "=" + records[i]
}
recordString = tbNameStr + rStr
print("RECORD STRING: \(recordString)")
let requestURL = URL(string: PATH_TO_API_FOLDER + "queryWhereKeyContains.php?" + recordString)
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
let request = URLRequest(url: requestURL!)
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
//exiting if there is some error
if error != nil {
print("Error is: \(error!.localizedDescription)")
return
} else {
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any] {
theData = json
print("JSON: \(json)")
}
} catch let error { print("ERROR IN PARSING JSON: \(error.localizedDescription)") }
})
task.resume()
let flag = true
completionHandler(flag, theData)
}
I call that function in my ViewController.swift, like this:
let query = NJObject(tableName: HOTEL_TABLE_NAME)
query.whereKeyContains(columnName: HOTEL_NAME, record: "Hotel")
query.findObjectInBackground { (succ, objects) in
print("OBJECTS: \(objects)")
print("SUCCESS: \(succ)")
}
So, in the Xcode console, I correctly get my JSON data, but when printing the completion handler, data (printed as OBJECTS) is empty.
OBJECTS: [:]
SUCCESS: true
JSON: ["objects": <__NSArrayM 0x17004b4c0>(
{
address = "<null>";
createdAt = "2017-08-12 23:08:48";
description = "lorem ipsec dolor sit";
email = "<null>";
},
{
address = "<null>";
createdAt = "2017-08-14 06:19:10";
description = "lorem ipsec dolor sit";
email = "<null>";
})
]
One thing I noticed is that the console first prints the OBJECTS as and empty [:] and SUCCESS logs, then the JSON data.
So I am sure there's something wrong in my findObjectInBackground() function, I just can't figure out where the issue is.
You have to put the completion handler into the completion handler of the data task
You can omit the creation of the URLRequest, GET is the default, just pass the URL:
let task = session.dataTask(with: requestURL!, completionHandler: { data, response, error in
//exiting if there is some error
if error != nil {
print("Error is: \(error!.localizedDescription)")
completionHandler(false, [:])
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: Any] {
print("JSON: \(json)")
completionHandler(true, json) // the variable `theData` is not needed.
}
} catch let error { print("ERROR IN PARSING JSON: \(error.localizedDescription)") }
completionHandler(false, [:])
})
task.resume()
And do not pass .mutableContainers, it's meaningless in Swift
Side note: In Swift 3 this closure declaration is sufficient:
typealias CompletionHandler = (Bool, [String:Any]) -> Void
The problem is that you are calling the completion handler outside the completion handler of your network request, so the completion handler of your function returns before the async network request would return. You need to move it inside the completion handler of the request.
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any] {
theData = json
print("JSON: \(json)")
completionHandler(true, theData)
}
}
Is it possible that someone could show me how to get the names of these pizza places printing out? My application prints out the expected "Status Code: 200". However, my console only shows empty brackets []. I suspect that I am not pulling values from my JSON object properly.
I'm using this link for my API.
Link For API
Question
How can I properly fetch values from my serialized JSON object?
relevant code:
// Response
if let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200, let data = data {
print("Status Code: \(httpResponse.statusCode)")
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
if let pizzaPlaces = json["response"] as? [[String: AnyObject]] {
for place in pizzaPlaces {
if let name = place ["name"] as? String {
self.PizzaClass.append(name)
}
}
}
} catch {
print("Error Serializing JSON Data: \(error)")
}
print(self.PizzaClass)
}
}).resume()
You need to cast your NSJSONSerialization.JSONObjectWithData result as a [String:AnyObject].
let jsonObject = try NSJSONSerialization.JSONObjectWithData(returnedData, options: .MutableLeaves) as! [String: AnyObject]
Once you have that all you need to do is pay attention to what you're casting. Take the code below for an example. If we want to get our response object using jsonObject["response"] what kind of data structure do we have?
"response": {
"venues": [{
//... continues
}]
}
On the left we have "response" which is a string, on the right we have {} which is an AnyObject. So we have [String: AnyObject]. You just need to think about what object your dealing with piece by piece. Below is a working example that you can just paste into your application.
full working code:
func getJson() {
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.foursquare.com/v2/venues/search?client_id=0F5M0EYOOFYLBXUOKTFKL5JBRZQHAQF4HEM1AG5FDX5ABRME&client_secret=FCEG5DWOASDDYII4U3AAO4DQL2O3TCN3NRZBKK01GFMVB21G&v=20130815%20&ll=29.5961,-104.2243&query=burritos")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
guard let testResponse = response as? NSHTTPURLResponse else {
print("\(response)")
return
}
guard let status = HTTPStatusCodes(rawValue: testResponse.statusCode) else {
print("failed to unwrap status")
return
}
print(status)
switch status {
case .Created:
print("ehem")
case .BadRequest:
print("bad request")
case .Ok:
print("ok")
guard let returnedData = data else {
print("no data was returned")
break
}
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(returnedData, options: .MutableLeaves) as! [String: AnyObject]
guard let response = jsonObject["response"] as? [String: AnyObject] else { return }
guard let venues = response["venues"] as? [AnyObject] else { return }
guard let location = venues[0]["location"] as? [String:AnyObject] else { return }
guard let formattedAddress = location["formattedAddress"] else { return }
print("response: \n\n \(response)\n------")
print("venues : \n\n \(venues)\n-------")
print("location : \n\n \(location)\n------")
print("formatted address : \n \(formattedAddress)")
} catch let error {
print(error)
}
// update user interface
dispatch_sync(dispatch_get_main_queue()) {
print("update your interface on the main thread")
}
}
}
task.resume()
}
place this either in its own file our outside of the class declaration,
enum HTTPStatusCodes : Int {
case Created = 202
case Ok = 200
case BadRequest = 404
}
Not that this was what you are looking for, but since you are new to Swift take a look at Alamofire. It handles JSON serialization for you. And when you need to chain calls PromiseKit is super slick.
Alamofire.request(.GET, url).responseJSON {response in
switch (response.result) {
case .Success(let value):
let pizzas = JSON(value).arrayValue
for place in pizzaPlaces {
if let name = place ["name"] as? String {
self.PizzaClass.append(name)
}
}
case .Failure(let error):
if let data = response.data, let dataString = String(data: data, encoding: NSUTF8StringEncoding) {
print("ERROR data: \(dataString)")
}
print("ERROR: \(error)")
}
}