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
Related
I am sending an Alamofire request and inside of my completion handler I have:
if let jsonData = response.result.value {
result = jsonData
guard let data = result.data(using: .utf8) else { return}
guard let dictionary = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
print("Could not cast JSON content as a Dictionary<String, Any>")
return
}
print("dictionary: \(dictionary)")
if dictionary["status"] as! String == "false"{
//Do something
}
}
else{
result = "\(response.error)"
}
The result of printing dictionary is ["status":false, "value":A1]. Ultimately I want to use status for my if statement. However I get a crash on the if statement line: if dictionary["status"] as! String == "false" of Fatal error: Unexpectedly found nil while unwrapping an Optional value. I also tried changing the line to if dictionary["status"] as! Bool == false and I get the exact same error.
The json as returned from the request is:
{
"value": "A1",
"status": "false"
}
So my question is, what is the correct way to get the value for status out of dictionary?
Would something like this work?
struct jsonOut: Codable {
let value: String
let status: String
}
if let jsonData = response.result.value {
result = jsonData
guard let data = result.data(using: .utf8)
let status = try JSONDecoder().decode(jsonOut.self, from: data)
}
Since the JSON has the format:
{
"value": "A1",
"status": "false"
}
The correct way is using Codable with the same format as the JSON:
struct jsonOut: Codable {
let value: String
let status: String
}
if let jsonData = response.result.value {
result = jsonData
guard let data = result.data(using: .utf8)
let statusData = try JSONDecoder().decode(jsonOut.self, from: data)
print("status: \(statusData.status)"
}
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 am trying to loop through a JSON array which I am getting from an HTTP Request, but I am not sure how.
What I have tried is this:
var request = NSMutableURLRequest(url: url! as URL, cachePolicy: NSURLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: Double.infinity)
if Reachability.isConnectedToNetwork(){
request = NSMutableURLRequest(url: url! as URL, cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: Double.infinity);
}
let session = URLSession.shared
var getResp = false
var zinnen : [Zin] = []
let task = session.dataTask(with: request as URLRequest,
completionHandler: { data, response, error -> Void in
let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
for case let data in json {
if let zin = Zin(json: data) {
zinnen.append(zin)
}
}
})
task.resume()
And this is my struct:
struct Zin : CustomStringConvertible {
var description: String
let id : Int
let dutch_sentence : String
let polish_sentence : String
init(dictionary: [String: Any]) {
self.id = dictionary["id"] as? Int ?? 0
self.dutch_sentence = dictionary["dutch_sentence"] as? String ?? ""
self.polish_sentence = dictionary["polish_sentence"] as? String ?? ""
}
}
A sample of the JSON Array:
[
{
"id":"35",
"dutch_sentence":"Ja",
"polish_sentence":"Tak"
},
{
"id":"36",
"dutch_sentence":"Nee",
"polish_sentence":"Nie"
}
]
But in this I get the error
Type '[String: Any]??' does not conform to protocol 'Sequence'
Don't ignore the error! Both try? and optional downcast cause a nested optional (Optional<Optional<[String:Any]>>) which of course is not a sequence, not even when being casted to an array.
Handle the error, optional bind the result and cast the result to the more specified array [[String:String]]. According to the JSON the value for id is String not Int.
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [[String: String]] {
for zinData in json {
let zin = Zin(dictionary: zinData)
zinnen.append(zin)
}
}
} catch { print(error) }
PS: The initializer in the Zin class does not match the initializer in the parsing code. I'm using the version of the class. You have to change the type of id from Int to String
I have a JSON parsing issue with my Swift code below. The error I am getting says that my JSON output does not contain a key value.
My code:
Alamofire.request(url, method: .get, headers: headers).responseJSON { (response) -> Void in
let jsonValue = response.result.value as! NSDictionary
if let bpArray = jsonValue["value"] as? [NSDictionary]{
for results in bpArray {...}
Issue:
This conversion doesnt work: if let bpArray = jsonValue["value"] as? [NSDictionary]
My JSON Structure:
{
d: {
results: [
{
__metadata: {},
Key: "AFBWhULFHtKU4j4FhWCmKg==",
ParentKey: "AAAAAAAAAAAAAAAAAAAAAA==",
RootKey: "AFBWhULFHtKU4j4FhWCmKg==",
Partner: "MM-CARR-01",
Type: "2",
Description: "MM Demo Carrier Created for Single Stop / MA",
FrieghtOrder: {}
},
...
Assuming you want to access the results key so try like this:-
if let bpArray = jsonValue["results"] as? [String: AnyObject]{
//yourcode
}
Well your json structure haven't got any key named as value and that's why it's giving an error.
In order to get results array, you first need to get the object in which they are nested and for example 'g' in your case:
if let data = jsonValue["d"] as? [NSDictionary]{
if let resultsArray = data["results"] as? NSArray {
//your code
}
}
Please Use Swifty Json Pod And Try this code
pod 'SwiftyJSON'
In Your file where you get response
import SwiftyJSON
Then After Use This Code
switch response.result {
case .success(let JSON2):
print("Success with JSON: \(JSON2)")
// print("Request failed with error: \(response.response?.statusCode)")
if let response = JSON2 as? NSMutableDictionary
{
}
else if let response = JSON2 as? NSDictionary
{
if let data = response?.object(forKey: "d") as? NSDictionary
{
if let resultsArray = data?.object(forKey: "results") as? NSArray
{
}
}
}
else if JSON2 is NSArray
{
let swjson = JSON(response.result.value!)
print(swjson)
// callback(swjson,nil)
var myMutableDictionary = [AnyHashable: Any]()
myMutableDictionary["myArray"] = swjson
callback(myMutableDictionary as NSDictionary?,nil)
print("accc")
}
else if ((JSON2 as? String) != nil)
{
let userDic : [String : String] = ["quatid":JSON2 as! String]
print(userDic)
}
break
case .failure(let error):
print("Request failed with error: \(error)")
}
Remember it's better we not use NSArray & NSDictionary like things in SWIFT, SWIFT it self providing let, var keyword for various data type.
First you can create your model where you can save the data.
MyModel.swift
class MyModel: NSObject {
var ParentKey : Int?
init(jsonObject:[String:Any]) {
ParentKey = jsonObject["ParentKey"] as? String ?? ""
}
}
Viewcontroller.Swift
var myModel : [MyModel] = []
if let responseData = response["d"] as? [String:Any]{
if let dataObject = responseData["results"] as? [[String:Any]]{
self.myModel = dataObject.map({return MyModel(jsonObject: $0)})//for assigning data into model
}
}
As most people said, I was wrong with "value". Hussain's answer to using [String:AnyObject] Helped.
I am not sure if the below is neat to achieve, but it did the magic. App loaded as expected. Code expert below:
Solution:
if let bpData = jsonValue["d"] as? [String: AnyObject]{
for results in bpData {
let arrayInterim = results.value as? NSArray
for i in 0 ..< arrayInterim!.count {
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)")
}
}