Can't access JSON using SwiftyJSON - json

I am trying to access the JSON that I get via Alamofire:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseString {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}
,and the JSON that is being returned to me looks something like this:
{
"status":"success",
"object":[
{
"name":"Bob",
"age":"20 ",
},
{
"name": "Jane",
"age":"25"
},
]
}
and I am using SwiftyJSON to access the names:
func parseJSON(json: JSON) {
for result in json["object"].arrayValue {
print(result["name"].stringValue)
}
}
but it is not printing anything. Am I doing something wrong?

responseJSON should be used instead of responseString

Your JSON is invalid
{
"status": "success",
"object": [
{
"name": "Bob",
"age": "20 ",
},
{
"name": "Jane",
"age": "25"
}, <--Delete this comma
]
}

Managed to figure out what was wrong with my code. When I did a POST request using Alamofire, I was returning the data back as a string: .responseString instead of JSON: .responseJSON
working code:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseJSON {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}

Replace responseString with responseJSON

Related

For Loop with json decode data error requires 'People' to conform to 'Sequence'

I am new to swift . I created simple playground and added the file with extension json into playground . I am trying to decode the result and print the ID by using for loop but , I am getting following error ..
For-in loop requires 'People.Type' to conform to 'Sequence'
Here is my json file ..
{
"id": "1",
"options": [{
"id": "11",
"options": [{
"id": "111",
"options": []
}]
},
{
"id": "2",
"options": [{
"id": "21",
"options": []
},
{
"id": "22",
"options": [{
"id": "221",
"options": []
}]
}
]
}
]
}
Here is the code .. I tried ..
struct People: Codable {
let id: String
let options: [People]
}
func loadJson(filename fileName: String) -> People? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(People.self, from: data)
print("// Printing the ID of the Decode Json")
for jsondata in jsonData {
print("ID: \(jsonData.id)")
}
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
loadJson(filename: "people1")
Here is the screenshot of the error ..
Here I got to run exactly what you are asking for, however I think you should probably consider renaming your struct to something like Person as #Vadian suggested.
struct People: Codable {
let id: String
let options: [People]
}
func loadJson(filename fileName: String) -> People? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(People.self, from: data)
printPeople(people: [jsonData])
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
func printPeople(people: [People]) {
for person in people {
print(person.id)
if (!person.options.isEmpty) {
printPeople(people: person.options)
}
}
}
loadJson(filename: "people")
This will print:
1
11
111
2
21
22
221

How to filter JSON and get value in iOS Swift?

I'm trying to filter JSON and get key & value to parse it. Here all JSON values are dynamic. Right now I need to find "type = object" if the type found is true then I need to check value ={"contentType" & "URL"}.
here is my JSON:
{
"date": {
"type": "String",
"value": "03/04/1982",
"valueInfo": {}
},
"Scanner": {
"type": "Object",
"value": {
"contentType": "image/jpeg ",
"url": "https://www.pexels.com/photo/neon-advertisement-on-library-glass-wall-9832438/",
"fileName": "sample.jpeg"
},
"valueInfo": {
"objectTypeName": "com.google.gson.JsonObject",
"serializationDataFormat": "application/json"
}
},
"startedBy": {
"type": "String",
"value": "super",
"valueInfo": {}
},
"name": {
"type": "String",
"value": "kucoin",
"valueInfo": {}
},
"ScannerDetails": {
"type": "Json",
"value": {
"accountNumber": "ANRPM2537J",
"dob": "03/04/1982",
"fathersName": "VASUDEV MAHTO",
"name": "PRAMOD KUMAR MAHTO"
},
"valueInfo": {}
}
}
decode code:
AF.request(v , method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).responseJSON { (response:AFDataResponse<Any>) in
print("process instance id api document view list::::",response.result)
switch response.result {
case .success:
let matchingUsers = response.value.flatMap { $0 }.flatMap { $0. == "object" }
print("new object doc:::", matchingUsers)
guard let data = response.value else {
return
}
print("new object doc:::", matchingUsers)
if let newJSON = response.value {
let json = newJSON as? [String: [String:Any]]
print("new object doc:::", json as Any)
// let dictAsString = self.asString(jsonDictionary: json)
let vc = self.stringify(json: json ?? [])
print("dictAsString ::: dictAsString::::==",vc)
let data = vc.data(using: .utf8)!
do{
let output = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: [String:String]]
print ("demo:::==\(String(describing: output))")
}
catch {
print (error)
}
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [String: [String:String]]
{
print("json array::::",jsonArray) // use the json here
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
}
self.view.removeLoading()
case .failure(let error):
print("Error:", error)
self.view.removeLoading()
}
}
How to get specific values from JSON? Any help is much appreciated pls...
Here is code from my playground with your json sample:
import Foundation
let json = """
{
"date": {
"type": "String",
"value": "03/04/1982",
"valueInfo": {}
},
"Scanner": {
"type": "Object",
"value": {
"contentType": "image/jpeg ",
"url": "https://www.pexels.com/photo/neon-advertisement-on-library-glass-wall-9832438/",
"fileName": "sample.jpeg"
},
"valueInfo": {
"objectTypeName": "com.google.gson.JsonObject",
"serializationDataFormat": "application/json"
}
},
"startedBy": {
"type": "String",
"value": "super",
"valueInfo": {}
},
"name": {
"type": "String",
"value": "kucoin",
"valueInfo": {}
},
"ScannerDetails": {
"type": "Json",
"value": {
"accountNumber": "ANRPM2537J",
"dob": "03/04/1982",
"fathersName": "VASUDEV MAHTO",
"name": "PRAMOD KUMAR MAHTO"
},
"valueInfo": {}
}
}
"""
let data = json.data(using: .utf8, allowLossyConversion: false)!
struct ObjectScanner: Decodable {
let contentType: String
let url: String
let fileName: String
}
enum ObjectScannerType {
case object(ObjectScanner)
}
struct Scanner: Decodable {
enum ScannerType: String, Decodable {
case object = "Object"
}
enum CodingKeys: String, CodingKey {
case type, value
}
let scanner: ObjectScannerType
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(ScannerType.self, forKey: .type)
switch type {
case .object:
let value = try container.decode(ObjectScanner.self, forKey: .value)
scanner = .object(value)
}
}
}
struct DateResponse: Decodable {
let type: String
let value: String
// let valueInfo // Not enough information in sample for me to decode this object
}
struct Response: Decodable {
enum CodingKeys: String, CodingKey {
case date
case scanner = "Scanner"
}
let date: DateResponse
let scanner: Scanner
}
let decoder = JSONDecoder()
do {
let response = try decoder.decode(Response.self, from: data)
print(response)
} catch {
print("Error decoding: \(error.localizedDescription)")
}
Note: this example is very unforgiving. Any missing value or type that is not supported will lead to a DecodingError. It's up to you to determine all possible types and what is optional and what is not.
I also didn't decode everything nor do I handle the date object to it's fullest
This is as json goes a very complex example. Everything in it is polymorphic: the date, the Scanner, the ScannerDetails, etc. You need to be very careful how you decode this and make sure you handle all possibilities. I would suggest that if you're starting out, you should explore simpler examples.
I also chose to use enums. Not something everyone would chose but its my preference for decoding polymorphic types such as these.
You can read my article about dealing with polymorphic types as well as unknown types here: https://medium.com/#jacob.sikorski/awesome-uses-of-swift-enums-2ff011a3b5a5

How to serialize JSON string to multidimensional NSDictionary

"[{\"person\":\"person1\",\"data\":{\"age\":\"10\",\"name\":\"John\"}},
{\"person\":\"person2\",\"data\":{\"age\":\"20\",\"name\":\"Jonathan\"}},
{\"person\":\"person3\",\"data\":{\"age\":\"30\",\"name\":\"Joe\"}}]"
Note that the value "data" is also a dictionary.
I have a JSON string like above and am trying to serialize like:
if let dataFromString = conf.data(using: .utf8, allowLossyConversion: false) {
let json = try JSON(data: dataFromString)
configuration = json.dictionary ?? [:]
}
However configuration is always an empty dictionary.
You need to parse the JSON you've as an array of dictionaries of type [[String: Any]]. The better modern approach is to use Decodable model to decode the JSON.
let string = """
[
{
"person": "person1",
"data": {
"age": "10",
"name": "John"
}
},
{
"person": "person2",
"data": {
"age": "20",
"name": "Jonathan"
}
},
{
"person": "person3",
"data": {
"age": "30",
"name": "Joe"
}
}
]
"""
let data = Data(string.utf8)
struct Person: Decodable {
let person: String
let data: PersonData
}
struct PersonData: Decodable {
let age, name: String
}
do {
let people = try JSONDecoder().decode([Person].self, from: data)
print(people)
} catch { print(error) }
For the JSON String,
let conf = "[{\"person\":\"person1\",\"data\":{\"age\":\"10\",\"name\":\"John\"}},{\"person\":\"person2\",\"data\":{\"age\":\"20\",\"name\":\"Jonathan\"}},{\"person\":\"person3\",\"data\":{\"age\":\"30\",\"name\":\"Joe\"}}]"
use JSONSerialization's jsonObject(with:options:) method to get the expected response.
if let conf = str.data(using: .utf8 ) {
do {
let dict = try JSONSerialization.jsonObject(with: data, options: []) as? [[String:Any]]
print(dict)
} catch {
print(error)
}
}

Order of JSON node changes while making POST request Swift

I was trying to post the following jSON body
request JSON :
let parameters = [
"createTransactionRequest": [
"merchantAuthentication": [
"name": "xxxxxxxx",
"transactionKey": "xxxxxxxxx"
],
"refId": "123456",
"transactionRequest": [
"transactionType": "authCaptureTransaction",
"amount": "5",
"payment": [
"opaqueData": [
"dataDescriptor": desc!,
"dataValue": tocken!
]
]
]
]
]
When I am trying to print(parameters) the order of node changes it looks like
["createTransactionRequest":
["refId": "123456",
"transactionRequest":
["payment": ["opaqueData": ["dataDescriptor": "COMMON.ACCEPT.INAPP.PAYMENT", "dataValue": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="]],
"transactionType": "authCaptureTransaction",
"amount": "5"],
"merchantAuthentication": ["name": "xxxxxxx", "transactionKey":
"6gvE46G5seZt563w"]
]
]
I am getting response like
{ messages = {
message = (
{
code = E00003;
text = "The element 'createTransactionRequest' in namespace
'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element
'refId' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of
possible elements expected: 'merchantAuthentication' in namespace
'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.";
}
);
resultCode = Error;
};
}
This is really annoying. anyones help will be highly grateful.
You need to change your data structure as follow:
struct Transaction: Codable {
let createTransactionRequest: CreateTransactionRequest
}
struct CreateTransactionRequest: Codable {
let merchantAuthentication: MerchantAuthentication
let refId: String
let transactionRequest: TransactionRequest
}
struct MerchantAuthentication: Codable {
let name: String
let transactionKey: String
}
struct TransactionRequest: Codable {
let transactionType: String
let amount: String
let payment: Payment
}
struct Payment: Codable {
let opaqueData: OpaqueData
}
struct OpaqueData: Codable {
let dataDescriptor: String
let dataValue: String
}
Testing
let json = """
{ "createTransactionRequest":
{ "merchantAuthentication":
{ "name": "YOUR_API_LOGIN_ID",
"transactionKey": "YOUR_TRANSACTION_KEY"
},
"refId": "123456",
"transactionRequest":
{ "transactionType": "authCaptureTransaction",
"amount": "5",
"payment":
{ "opaqueData":
{ "dataDescriptor": "COMMON.ACCEPT.INAPP.PAYMENT",
"dataValue": "PAYMENT_NONCE_GOES_HERE"
}
}
}
}
}
"""
let jsonData = Data(json.utf8)
do {
let transaction = try JSONDecoder().decode(Transaction.self, from: jsonData)
print(transaction)
// encoding
let encodedData = try JSONEncoder().encode(transaction)
print(String(data: encodedData, encoding: .utf8)!)
} catch {
print(error)
}
{"createTransactionRequest":{"merchantAuthentication":{"name":"YOUR_API_LOGIN_ID","transactionKey":"YOUR_TRANSACTION_KEY"},"refId":"123456","transactionRequest":{"transactionType":"authCaptureTransaction","amount":"5","payment":{"opaqueData":{"dataValue":"PAYMENT_NONCE_GOES_HERE","dataDescriptor":"COMMON.ACCEPT.INAPP.PAYMENT"}}}}}

How to parse JSON in Swift?

I have some JSON data that looks like this which I am trying to parse in Swift.
[
[
{
a: "1",
b: "2"
},
[
{
c: "3",
},
{
d: "4",
}
]
]
]
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let myArray = json[0] as? [[AnyObject]] {
for myObject in myArray {
print("This works!\(myObject)")
}
}
However nothing I try seems to work - any help would be appreciated.
you can use SwiftyJSON - https://github.com/SwiftyJSON/SwiftyJSON
or create a class based on your JSON scheme try to parse with it.
like:
class object
{
let data = Array<subObject>()
}
class subObject
{
let subData = Array<Dictionary<AnyObject,AnyObject>>()
}
This snippet is not JSON. If it was JSON, the keys would be strings, like this:
[
[
{
"a": "1",
"b": "2"
},
[
{
"c": "3",
},
{
"d": "4",
}
]
]
]
And anyway in your screenshot we see that your JSON has already been parsed!
What you show in the image is not JSON either, but an array containing arrays and dictionaries...
But let's say your JSON is actually valid and the missing quotes are just a copy/paste problem.
Then to achieve your goal you have to cast the result of NSJSONSerialization to the correct JSON format, then you can access the inner objects.
Like this, for example:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[AnyObject]] {
if let myArray = json.first {
for myObject in myArray {
print("This works!\(myObject)")
}
}
}
} catch let error as NSError {
print(error.localizedDescription)
}