Swift: NSDictionary as NSArray - json

let voicemailFiles = voicemail.value( forKey: "voicemail") as! [AnyObject]
// Could not cast value of type '__NSDictionaryI' (0x10ca8a228) to 'NSArray' (0x10ca89d78)
let voicemailFiles = voicemail.value( forKey: "voicemail") as! [String : String]
// Could not cast value of type '__NSArrayI' (0x104df9448) to 'NSDictionary' (0x104df7fa8).
When trying to put the JSON ( as seen below) into a variable, i am hitting the above errors for the 2 methods of casting for "voicemail".
let config = voicemail.value(forKey: "config") as AnyObject
This line for the key of config works perfectly.
The variable of voicemail is an [AnyObject] value of the key, voicemailboxes
{
"voicemailboxes": [
{
"config": {
"id": "5",
"description": "Test"
},
"voicemail": [
{
"id": "id001",
"caller": "...",
"caller_UK": "...",
"called": "+...",
"called_UK": "...",
"received": "...",
"duration_seconds": "..."
},
{
"id": "id002",
"caller": "...",
"caller_UK": "...",
"called": "..."
}
]
}
]
}

voicemailboxes is an array of Dictionary.
voicemail is also an array of Dictionary.
Need to parse them appropriately.
On playground:
let json = """
{
"voicemailboxes": [
{
"config": {
"id": "5",
"description": "Test"
},
"voicemail": [
{
"id": "id001",
"caller": "...",
"caller_UK": "...",
"called": "+...",
"called_UK": "...",
"received": "...",
"duration_seconds": "..."
},
{
"id": "id002",
"caller": "...",
"caller_UK": "...",
"called": "..."
}
]
}
]
}
"""
let data = json.data(using: .utf8)!
let jsonDict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String:Any]
let voicemailboxes = jsonDict["voicemailboxes"] as! [Any]
let voicemailboxesfirst = voicemailboxes.first as! [String:Any]
let voicemail = voicemailboxesfirst["voicemail"] as! [Any]
let voicemailfirst = voicemail.first as! [String:Any]
print(voicemailfirst)
Output:
["received": ..., "called": +..., "id": id001, "caller_UK": ..., "duration_seconds": ..., "caller": ..., "called_UK": ...]

As per your JSON it is clear that
voicemailboxes is [[string:Any]] (Array of Dictionary) and
voicemail is [[String:String]] (Array of Dictionary)
NOTE: guard or if let required to check correct response below is just example
You can access it like
((dictMain["voicemailboxes"] as! [[String:Any]]).first!["voicemail"] as! [[String:Any]])
Hope it is helpful to you

use below code
if let any = voicemail.value( forKey: "voicemail") {
if let tmpArray = any as? Array {
let voicemailFiles = tmpArray
}
}

Related

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)
}
}

swift json parsing based on parameter

I am having the following web service response in which I need parse the parameters based on "MainServiceCategories_ID"
Here is the response
{
"Entity": {
"ID": 20021,
"UserTypeID": 1,
"UserType": null,
"UserID": 30046,
"Code": "lPx1lTEq",
"Name": "بدراء",
"EnglishName": "Badra",
"IconProfileImageID": "",
"MainImageProfileImageID": "EED372C3-5C4F-E711-8100-0CC47A343427",
"LocationLng": 78.37021,
"LocationLat": 17.432563,
"Services": [
{
"ID": 11788,
"MainServiceCategories_ID": 3,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “John”,
"EnglishName": “Johnny”,
},
{
"Parent_ID": 6,
"Name": “Ronny”,
"EnglishName": “Ronny”,
}]
},
{
"ID": 11788,
"MainServiceCategories_ID": 2,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “Samuel”,
"EnglishName": “Samuel”,
},
{
"Parent_ID": 6,
"Name": “Badri”,
"EnglishName": “Badri”,
}]
},
{
"ID": 11788,
"MainServiceCategories_ID": 3,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “emma”,
"EnglishName": “Emma”,
},
{
"Parent_ID": 6,
"Name": “Sean”,
"EnglishName": “Sean”,
}]
}]
this is the code I am writing to do it
do{
let entityDic = responseDictionary["Entity"] as? [String: Any]
let servicesDic = entityDic?["Services"] as? [Any]
for i in 0 ..< servicesDic!.count {
let services = servicesDic?[i] as? [String: Any]
let availableServices = services!["EnglishName"]
servicesNamesArr.append(availableServices! as! String)
let children = services!["Children"]
childrenServices.append(children!)
let MainServiceCategories_ID = services!["MainServiceCategories_ID"]
MainServiceCategoriesID.append(MainServiceCategories_ID!)
}
print("childrenServices \(childrenServices)")
}
catch let error{
print(error)
}
I am able to get upto children dictionaries. Now the thing is I am trying to parse "English name" under children section and separate them based on "MainServiceCategories_ID" where I am getting fatal error in unwrapping the value.
for example if MainServiceCategories_ID =1 then that "English Name" need to be store in an array and if MainServiceCategories_ID =2 then into another array
The problem is, you are trying to parse "EnglishName" as a key of an element of the "Services" array and not as a key of a "Children" element. "Services" does not have a key "EnglishName", so you can't store that in servicesNamesArr. servicesDic should also be an Array of Dictionaries and not an array of Any objects.
See below code using guard statements using safe optional unwrapping:
do{
guard let entityDic = responseDictionary["Entity"] as? [String: Any] else {return}
guard let servicesDic = entityDic?["Services"] as? [[String:Any]] else {return}
for service in services {
guard let MainServiceCategoryID = service["MainServiceCategories_ID"] as? Int else {return}
MainServiceCategoriesID.append(MainServiceCategoryID)
guard let children = service["Children"] as? [[String:Any]] else {return}
childrenServices.append(children)
if MainServiceCategoryID == 3 {
for child in children {
if let availableService = child["EnglishName"] as? String {
servicesNamesArr.append(availableService)
}
}
}
}
print("childrenServices \(childrenServices)")
} catch let error{
print(error)
}

Read GeoJSON data from MongDB in Xcode 8.1 Swift 3?

I have a NodeJS API that queries a MongoDB cluster and returns nearby data in the following format. The issue is I can't enumerate the locations with Swift 3 and XCode 8.1.
[
{
"_id": "57b03fa32c6835946afd358c",
"location": {
"coordinates": [
144.2,
-34
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 01",
"url": "http://www.url.com/Resource01.html"
},
{
"_id": "34b03fa32c6835946afd358c",
"location": {
"coordinates": [
154.2,
-35.3
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 02",
"url": "http://www.url.com/Resource02.html"
}
]
This is my Query code.
let json = try! JSONSerialization.jsonObject(with: data)
print(json)
if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let jsonbranch = statusesArray?[0] as? [String: AnyObject],
let therecord = jsonbranch["_id"] as? String {
print ("_id: " + therecord)
}
I tried to use SwiftyJSON but it does not work either?
Solved:
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[0]["name"] as? String {
print ("name: " + name)
}
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[1]["name"] as? String {
print ("name: " + name)
}

Unwrapping Json Swift (found nil)

i currently trying to decode Json in Xcode, but i not succed to get one of them.
This is what i get :
[
{
"id": "1",
"title": "bmw",
"price": "500.00",
"description": "330",
"addedDate": "2015-05-18 00:00:00",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "32767",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "2",
"subcategory_label": "Motos",
"bdd": {}
}
"pictures":
[
{ "name": "http://cars.axlegeeks.com/sites/default/files/4315/media/images/2014_BMW_Z4_sDrive28i_3790993.jpg"
}
]
}
]
And i want to get the value of "name" for the "Pictures" lines but i have the error "unexpectedly found nil while unwrapping value".
For the others values i proceed this way :
let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as! NSDictionary
//Browse into JSON to get datas
let resp = jsonData["0"] as! NSDictionary
let user_nameR = resp["user_name"] as! String
let user_zipCodeR = resp["user_zipCode"] as! String
let titleR = resp["title"] as! String
let priceR = resp["price"] as! String
let descriptionR = resp["description"] as! String
Thank's for your help !
Pictures is in not in the subdictionary your other values are. This should work, but you should check all values if they are nil before you force cast them.
if let pictureArray = jsonData["pictures"] as? NSArray
{
if let pictureDict = pictureArray.firstObject as? NSDictionary
{
if let pictureName = pictureDict.objectForKey("name") as? String
{
NSLog("Picture name: %#", pictureName)
}
}
}
jsonData contains two sub-dictionaries, one without a key and one with key 'pictures'. Pictures is an array containing one sub-dictionary.