How to iterate array of dictionaries having nested dictionary? - ios

I have JSON
http://maps.googleapis.com/maps/api/directions/json?&origin=28.594517,77.049112&destination=28.654109,77.34395&travelMode=DRIVING&provideRouteAlternatives=false&sensor=false
I want to access all the values in distance which is in steps.
Here is my code
class Router {
var getValue = Double()
func downloadData(complete: downloadComplete) {
let currentURL = URL(string:getURL)!
Alamofire.request(currentURL).responseJSON { (responseJSON) in
let result = responseJSON
// print(result)
if let dict = result.value as? Dictionary<String,AnyObject>{
if let routes = dict["routes"] as? [Dictionary<String, AnyObject>]{
if let legs = routes[0]["legs"] as? [Dictionary<String, AnyObject>]{
if let steps = legs[0]["steps"] as? [Dictionary<String, AnyObject>]{
for index in steps{
if let distance = steps["distance"] as? Dictionary<String,AnyObject>{
if let value = distance["value"] as? Double{
self.getValue = self.getValue + value
print(self.getValue)
}
}
}
}
}
}
}
}
complete()
}
I am getting error in:
if let distance = steps["distance"] as? Dictionary<String,AnyObject>{
which says:
Cannot subscript a value of type '[Dictionary]' with an index of type string
How can I access this?

You are trying to access the value of an array of dictionaries by key. You should change steps["distance"] to index["distance"].
if let distance = index["distance"] as? Dictionary<String,AnyObject>{
if let value = distance["value"] as? Double{
self.getValue = self.getValue + value
print(self.getValue)
}
}

The error is clear.
steps["distance"] is an array of dictionaries, which can be accessed like steps[0],steps[1].
You need to change following line
if let distance = steps["distance"] as? Dictionary<String,AnyObject>
to
if let distance = index["distance"] as? Dictionary<String,AnyObject>

Related

How to include firebase snapshot key value? [Swift]

Please anyone who would show me how to include the snapshot key value along with children value that I already append to my array (forgot to include it and now remember I have to) ... aside from that something really I couldn't understand when I tried to solve my own issue, by testing the value first by using this method: print(rooms.popFirst().key!) half of my database values got nil value ?!! and if I don't include that method everything works fine anyways if you can't imagine that nonetheless I really wish your suggestion or advice for getting all data with their own key value...
This is my code so far:
Database.database().reference().child("rooms").observe(.value, with: { (snapshot) in
print()
var rooms = snapshot.value as! [String:AnyObject]
for(_,value) in rooms {
if (rooms.popFirst()?.key) != nil{
let title = value["title"] as? String
let description = value["description"] as? String
let roomPictureUrl = value["Room Picture"] as? String
let longitude = value["Longtitude"] as? String
let latitude = value["Latitude"] as? String
let dateFrom = value["Date From"] as? String
let dateTo = value["Date To"] as? String
let owner = value["Owner"] as? String
let myRooms = Room(roomID: "XXX",title: title!, description: description!, roomPicutreURL: roomPictureUrl!, longitude: longitude!, latitude: latitude!, dateFrom: dateFrom!, dateTo: dateTo!, owner: owner!)
//print(rooms.popFirst()?.key)
self.rooms.append(myRooms)
self.tableView.reloadData()
}
}
})
Try this:
Database.database().reference().child("rooms").observe(.value, with: { (snapshot) in
var rooms = snapshot.value as! [String:AnyObject]
let roomKeys = Array(rooms.keys)
for roomKey in roomKeys {
guard
let value = rooms[roomKey] as? [String:AnyObject]
else
{
continue
}
let title = value["title"] as? String
let description = value["description"] as? String
let roomPictureUrl = value["Room Picture"] as? String
let longitude = value["Longtitude"] as? String
let latitude = value["Latitude"] as? String
let dateFrom = value["Date From"] as? String
let dateTo = value["Date To"] as? String
let owner = value["Owner"] as? String
let myRooms = Room(roomID: "XXX",title: title!, description: description!, roomPicutreURL: roomPictureUrl!, longitude: longitude!, latitude: latitude!, dateFrom: dateFrom!, dateTo: dateTo!, owner: owner!)
print(roomKey)
self.rooms.append(myRooms)
self.tableView.reloadData()
}
}
})
To get the key from snapshot you can use following lines of code it will give you result like -> Kqwewsds12 -> your child Details
let dictValues = [String](snapshot.keys)
print(dictValues[0]) //Output -- Kqwewsds12

In the mentioned url i need to get only first dictionary from the url?

In this order detail array i am having 10 dictionaries but i need to display only first dictionary can any one help me how to implement this ?
http://www.json-generator.com/api/json/get/bUKEESvnvS?indent=2
here is my code shown below
func downloadJsonWithURL() {
let url = NSURL(string: self.url)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
self.orderdetailsArray = (jsonObj!.value(forKey: "Orders detail") as? [[String: AnyObject]])!
for array in self.orderdetailsArray {
let key = "OrderId"
let value = "#1000501"
for (key,value) in array{
if let addressDict = array as? NSDictionary{
if let orderid = addressDict.value(forKey: "OrderId"){
self.orderid.append(orderid as! String)
}
if let orderdate = addressDict.value(forKey: "OrderDate"){
self.orderdate.append(orderdate as! String)
}
if let subtotal = addressDict.value(forKey: "SubTotal"){
self.subTotal.append(subtotal as! Int)
}
if let Shipping = addressDict.value(forKey: "Shipping"){
self.shippingPrice.append(Shipping as! Int)
}
if let tax = addressDict.value(forKey: "Tax"){
self.tax.append(tax as! Int)
}
if let grandtotal = addressDict.value(forKey: "GrandTotal"){
self.grandTotal.append(grandtotal as! Int)
}
if let shippingAddress = addressDict.value(forKey: "ShippingAddress"){
self.shippingAddress.append(shippingAddress as AnyObject)
}
if let shippingMethod = addressDict.value(forKey: "ShippingMethod"){
self.shippingMethod.append(shippingMethod as AnyObject)
}
if let billingAddress = addressDict.value(forKey: "BillingAddress"){
self.billingAddress.append(billingAddress as AnyObject)
}
if let paymentMethod = addressDict.value(forKey: "PayMentMethod"){
self.paymentMethod.append(paymentMethod as AnyObject)
}
self.itemsArray = addressDict.value(forKey: "Items detail") as! [[String : AnyObject]]
}
}
}
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
Do this. :
let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
guard let Ordersdetail = jsonObj["Orders detail"] as? [NSDictionary] else {
print("Cannot find key 'Orderdetails' in \(jsonObj)")
return
}
To access the contents of the first dictionary do this:
var orderid = Ordersdetail[0]["OrderId"]!
var shippingadress = Ordersdetail[0]["ShippingAddress"]!
var total = Ordersdetail[0]["GrandTotal"]!
var subtotal = Ordersdetail[0]["SubTotal"]!
var tax = Ordersdetail[0]["Tax"]!
var shipping = Ordersdetail[0]["Shipping"]!
Hi if you want first dictionary of that
self.orderdetailsArray
then
if let firstDictInfo = self.orderdetailsArray.first as? [String:Any] {
// Do your stuff here
print(firstDictInfo["OrderId"])
}
Instead of looping through the whole dictionary is dictionaries, you should just take the first dictionary and only parse that. There was also quite a few other conceptual problems with your code. In Swift, don't use NSDictionary, but use the native Swift version, Dictionary, which keeps the type information of its contents. Also, use conditional casting to make sure your program doesn't crash even if the received data is wrong/unexpected and don't use force unwrapping of optionals.
Also, when parsing a JSON response in Swift, in general it is not necessary and not a good idea to iterate through the key-value pairs of the dictionaries in the response. You should know what data structure you expect, otherwise you can't parse it properly and since you can directly access dictionary values in Swift if you know the key it corresponds to, there's no need to iterate through the dictionary in a loop.
func downloadJsonWithURL() {
let url = URL(string: self.url)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = (try? JSONSerialization.jsonObject(with: data!, options: .allowFragments)) as? [String:Any] {
guard let self.orderdetailsArray = jsonObj["Orders detail"] as? [[String: AnyObject]] else {return}
guard let firstOrderDetails = self.orderdetailsArray.first else {return}
let key = "OrderId"
let value = "#1000501"
if let ordered = firstOrderDetails["OrderId] as? String {
self.orderid.append(orderid)
}
if let orderdate = firstOrderDetails["OrderDate"] as? String{
self.orderdate.append(orderdate)
}
if let subtotal = firstOrderDetails["SubTotal"] as? Int{
self.subTotal.append(subtotal)
}
if let shipping = firstOrderDetails["Shipping"] as? Int{
self.shippingPrice.append(shipping)
}
if let tax = firstOrderDetails["Tax"] as? Int{
self.tax.append(tax)
}
if let grandtotal = firstOrderDetails["GrandTotal"] as? Int{
self.grandTotal.append(grandtotal)
}
if let shippingAddress = firstOrderDetails[ "ShippingAddress"] as? AnyObject{ //why don't you store it as a String?
self.shippingAddress.append(shippingAddress)
}
if let shippingMethod = firstOrderDetails[ "ShippingMethod"] as? AnyObject{
self.shippingMethod.append(shippingMethod)
}
if let billingAddress = firstOrderDetails[ "BillingAddress"] as? AnyObject {
self.billingAddress.append(billingAddress)
}
if let paymentMethod = firstOrderDetails ["PayMentMethod"] as? AnyObject{
self.paymentMethod.append(paymentMethod)
}
guard let itemDetails = firstOrderDetails["Items detail"] as? [[String : AnyObject]] else {return}
self.itemsArray = itemDetails
}
}
}
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
I haven't compiled and run the code, so make sure you check for any typos/inconsistencies. Also, make sure you change the types of the objects you store are AnyObjects to specific types.

Ambiguous use of subscript. Array Swift IOS

I try to compile on device but i get this error. Any help?. In the simulator works perfectly.
I get an ambiguous use of subscript error in the following code and was hoping somebody else has encountered this and know the fix.
case .Success:
if response.response?.statusCode == 200 {
print ("Respuesta 200")
if let value = response.result.value {
let respuestaJSON = JSON(value)
let objsonUSUARIOS = respuestaJSON["d"].object
let arrayUsuarios = objsonUSUARIOS["results"]!
//print ("Usuarios: ",String(arrayUsuarios))
for i in 0 ..< arrayUsuarios!.count{
let boletines = boletinJSON()
if let item = arrayUsuarios![i] as? [String: AnyObject]{
)
if let person = item["Title"] as? String
{
boletines.name = person
}
if let person = item["Portada"] as? String
{
boletines.imagen = person
}
if let person = item["Created"] as? String
{
boletines.fecha = person
}
if let person = item["AttachmentFiles"] as? [String: AnyObject] {
if let itemAttach = person["__deferred"] as? [String: AnyObject]{
if let itemdeferred = itemAttach["uri"] as? String {
boletines.urldescarga = itemdeferred
}
}
}
self.boletin.append(boletines)
self.view.hideToastActivity()
}
}
}
self.tableView.reloadData()
// self.view.hideToastActivity()
}
Inform the compiler what the intermediary object objsonUSUARIOS is of type
let objsonUSUARIOS = respuestaJSON["d"].object
After the above statement, the compiler does not know what kind of object he is dealing with. So make sure that you can actually do all the casting as below
let objsonUSUARIOS = respuestaJSON["d"].object as! Dictionary
let arrayUsuarios = objsonUSUARIOS["results"]! as! Array
The problem is that you have not specified the type of object arrayUsuarios is Array, so try to explicit type cast the arrayUsuarios Array
let arrayUsuarios = objsonUSUARIOS["results"] as! [[String: AnyObject]]

Extracting values from anyobject dictionary into array

My other question was marked as being identical to another but it didn't answer the problem I was having.
Here is the code:
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<NSObject, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<NSObject, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<NSObject, AnyObject>>
let steps = legs[0]["steps"]!
for i in 0...steps.count - 1 {
let step_coordinate = steps[i]["start_location"]!
print(step_coordinate!["lat"]!!)
}
}
The print statement gives this result
40.7609205
40.7640121
40.7595325
40.7501637
40.7481923
40.7393448
40.7252038
40.7225337
40.718295
but if I swap the print statement out to grab the values and put them in an array I get the fatal error: found nil.
Can someone explain why this is the case? How can I grab these values if not through a for loop?
Here's a cleaner version of your code.
Rules:
Don't force unwrap anything!
Optionally cast values coming from [NSObject: AnyObject] lookups.
Use guard statements and if let to safely unwrap optionals.
Don't index arrays that might be empty without checking first.
if status == "OK" {
guard let routes = dictionary["routes"] as? [[NSObject: AnyObject]] else { return }
self.selectedRoute = routes.first ?? [:]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as? [NSObject: AnyObject] ?? [:]
guard let legs = self.selectedRoute["legs"] as? [[NSObject: AnyObject]] else { return }
let firstleg = legs.first ?? [:]
guard let steps = firstleg["steps"] as? [[NSObject: AnyObject]] else { return }
for step in steps {
if let step_coordinate = step["start_location"] as? [NSObject: AnyObject] {
if let lat = step_coordinate["lat"] as? Double {
print(lat)
// append lat to array of lats
lats.append(lat)
}
}
}
}

Parsing data using NSJSONSerialization.JSONObjectWithData() but cannot access Array groups only strings

I've downloaded the data below which is in Json format.
{"name":"Shropshire Outage","nc_lead":"John Smith","dma":"11/111","username":"vwaghx1","status":"REOPENED","sapOrder":"12341245","ccsText":"123","nbPropAtRisk":12,"logs":[{"dateTime":"2016-04-07 20:02:42","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":null,"task":"CUSTPOORSUPPLIES","id_log":1489},{"dateTime":"2016-04-07 20:03:35","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":1238768765,"task":"PRESSURELOGGER","id_log":1490},{"dateTime":"2016-04-07 20:04:36","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":7692466478,"task":"CUSTSUPPLIESRESTOREDSOME","id_log":1491}],"id_event":601,"region":"Shropshire","trigger":"No Supply Call”,”valveOps":[{"dateTime":"2016-04-07 20:06:12","user":"vwaghx1","uid":7866756788,"x":678666,"y":723325,"description”:”Burst main downstream valve","id_valve_op":523},{"dateTime":"2016-04-07 20:05:31","user":"vwaghx1","uid":5674456470,"x":344534,"y":723433,"description":"Valve to separate both rezones","id_valve_op":522},{"dateTime":"2016-04-14 12:32:00","user":"vwaghx1","uid":1234512345,"x":123123,"y":123123,"description":"test","id_valve_op":541}],"images":[{"name":"After improvement.jpg","dateTimeCreated":"2016-04-08 14:10:30","contentType":"image/jpeg","caption":null,"uuid":null,"fileExtension":"jpeg","id_image":661},...]}
However, when I try to parse it using the code below, I can only access the string values such as "name","nc_lead", "region" etc.
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let nameStr = dict["name"] as? String {
incidentList.valueStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.valueStr = codeStr
}
if let region = dict[“region”] as? String {
incidentList.valueStr = region
}
if let ncLead = dict[“nc_lead”] as? String {
incidentList.valueStr = ncLead
}
I need to access the group values like "logs", "images" and "valveOps", which have their own string values in arrays.
How can I change my code so that I can access the strings as I am now and also load the groups into arrays?
You can try like this way, declare 3 array first.
var logArr: [[String: AnyObject]] = [[String: AnyObject]]()
var imageArr: [[String: AnyObject]] = [[String: AnyObject]]()
var valveArr: [[String: AnyObject]] = [[String: AnyObject]]()
Now use this array where you are getting response
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let nameStr = dict["name"] as? String {
incidentList.valueStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.valueStr = codeStr
}
if let region = dict["region"] as? String {
incidentList.valueStr = region
}
if let ncLead = dict["nc_lead"] as? String {
incidentList.valueStr = ncLead
}
if let logs = dict["logs"] as? [[String: AnyObject]] {
self.logArr = logs
}
if let valveOps = dict["valveOps"] as? [[String: AnyObject]] {
self.valveArr = valveOps
}
if let images = dict["images"] as? [[String: AnyObject]] {
self.imageArr = images
}

Resources