Ok so im having trouble drilling down into the response json that is retrieved in the below code.
Snapshot 1:
Snapshot 2:
I get the json above as a response, yet when I try to drill down into the json I cannot access the key "Address" or any other key that is held under bookings. it finds bookings but then assigns the variables i created for each key's value (address, state, zipcode, and city) and assigns these variables as null. My only theory is that the response json has "()" right after bookings instead of the normal "{}". Those brakets do appear after the parentheses, so how would i drill into that with out a key? I am still new to the app dev world so i could be completely wrong, just this request method has worked for me in the past when i've received "{}" after the first key.
1) You are using method valueForKeyPath() to get value from dictionary.
Change it to valueForKey().
2) Value for key "bookings" will give you array.
Try this code.
let data = JSON as! NSDictionary;
//value for key "bookings" will give you array
if let bookings = data.valueForKey("bookings") as? NSArray {
let bookingObj = bookings[0] as! NSDictionary;
self.address = bookingObj.valueForKey("address");
self.state = bookingObj.valueForKey("state");
self.zip = bookingObj.valueForKey("zip");
self.city = bookingObj.valueForKey("city");
}
FYI Please Note that, method valueForKeyPath() returns array of value for particular key from the array of dictionaries.
e.g. suppose you have multiple objects of bookings array, and you use
let arrayAddresses = bookings.valueForKeyPath("address") as! NSArray
this will return string array containing only address of all object.
Another point, '()' means Array Value, '{}' means Dictionary value.
I'd suggest using Swift types (like [String: AnyObject]) instead of Foundation types (like NSDictionary), and on top of that, you should print out when something fails so you know what's wrong. So starting from your let data = ... line, try this instead:
if let data = JSON as? [String: AnyObject],
bookings = data["bookings"] as? [[String: AnyObject]],
booking = bookings[0] {
self.address = booking["address"] as? String
self.state = booking["state"] as? String
self.zipCode = booking["zip"] as? String
self.city = booking["city"] as? String
print(self.address)
} else {
print("Couldn't parse booking from JSON")
}
More on why typing is important (and why you should use [[String: AnyObject]] instead of NSArray) in this article. You can be more specific and more concise if you use proper types.
Related
I am trying to read a JSON output from a web app. This output is:
[{"group_name":"XYZ","adminof":0}]
I have a struct that looks like:
struct grouplistStruct{
var group_name : String
var adminof : Any
}
The code that I am using is:
let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
for jsonResult in jsonArray{
let loc = grouplistStruct(group_name: jsonResult["group_name"], adminof: jsonResult["adminof"])
I can see that jsonArray reads the value correctly. Similarly in the for loop, jsonResult is also reading the value correctly
But when I try to assign this value to a Struct variable, it shows an error:
Type 'Any' has no subscript members
Why is that happening? Sorry I am new to Swift so I am learning all this.
Since your json data is an array containing dictionaries like this:
[{"group_name":"XYZ","adminof":0}]
You are getting the error
Type 'Any' has no subscript members
because you are downcasting the json as an array of Any and in swift Any (as the name suggests) represents any type like Int, Double or Dictionary of type [String: String] as you know that Int or Double can not have subscript like someInt["subscript"]
So you need to downcast to this specific type using [[String: Any]] .
This represents an array containing the dictionaries of type [String: Any]. This will work because dictionaries can have subscript members e.g someDict["group_name"]
Hence you should use [[String: Any]] instead of [Any] in this statement try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
I am making a call to Crypto Compares API to get all of the tickers along with their data (https://www.cryptocompare.com/api/data/coinlist/). I am having difficulty finding what the data type is of the returned json. I am able to turn it into a [String: Any], but the value looks like it also contains two dictionaries. Here is my code where I try to cast the json object into the dictionary.
guard let responseDictionary = responseObject as? [String: Any] else {
print("WRONG")
return
}
The code above successfully works, but I am not able to access the rest of the dictionary. I have also tried [String: [String: Any]] and most variations of it. Just for reference.. I am trying to access the coin name in the return.
***UPDATE: For anyone interested I had to save the responseDictionary["Data"] as! [String: [String: String]] then I could access the rest of the data as a dictionary, however when casting the responseObject it would only let me use [String: Any] instead of [String: [String: Any]]
In your case, since you are not sure about the format of the dictionary, use dump to print it out beautifully. Then you can figure out a propert way of casting using guard let
Try this out
dump(responseObject)
in school we're creating a program to track Sailing Races.
I'm currently developing the GPS Tracker App for the sailing teams.
The JSON to send to our Api must look like this:
{"hash":"asdh832","positions":[{"longitude":13.340532999999999,"latitude":52.4965431,"time":1488182463461},{"longitude":13.3175489,"latitude":52.4927039,"time":1488195535705},{"longitude":13.3175489,"latitude":52.4927039,"time":1488195536657}]}
First the Hash for the Team and positions in a Array(if the smartphone doesn't have a internet connection atm to send them later)
I have a "positions" Array Dictionary:
var positions = Array<Dictionary<String,String>>()
positions.append( ["longitude":String(location.coordinate.longitude),
"latitude":String(location.coordinate.latitude),
"time":String(Int64(location.timestamp.timeIntervalSince1970 * 1000.0))])
// Times 2 to test
positions.append( ["longitude":String(location.coordinate.longitude),
"latitude":String(location.coordinate.latitude),
"time":String(Int64(location.timestamp.timeIntervalSince1970 * 1000.0))])
let data2 = try JSONSerialization.data(withJSONObject: positions, options: [])
let dataString2 = String(data: data2,encoding: String.Encoding.utf8)!
print(dataString2)
The Result of print(dataString2) is:
[{"latitude":"52.4965211222075","longitude":"13.3405919673345","time":"1488194768467"},{"latitude":"52.4965211222075","longitude":"13.3405919673345","time":"1488194768467"}]
which is correct. Now I want to combine it with a the Hash:
let params: Dictionary<String, String> = ["hash":"asdh832","positions": dataString2]
let data = try JSONSerialization.data(withJSONObject: params , options: [])
let dataString = String(data: data,encoding: String.Encoding.utf8)!
but the now the result after "positions:" looks kinda weird:
{"hash":"asdh832","positions":"[{\"latitude\":\"52.4966040328522\",\"longitude\":\"13.3402242104124\",\"time\":\"1488195406482\"},{\"latitude\":\"52.4966040328522\",\"longitude\":\"13.3402242104124\",\"time\":\"1488195406482\"}]"}
without these extra " and \ it would be correct but I just don't know how to build it like this.
I'm using Swift 3 with Xcode 8.2.1
Make JSON string at last means don't create JSON string from Array positions instead of that set that Array with your params dictionary with key positions instead of setting string.
var positions = Array<Dictionary<String,String>>()
positions.append(["longitude":String(location.coordinate.longitude),
"latitude":String(location.coordinate.latitude),
"time":String(Int64(location.timestamp.timeIntervalSince1970 * 1000.0))])
positions.append(["longitude":String(location.coordinate.longitude),
"latitude":String(location.coordinate.latitude),
"time":String(Int64(location.timestamp.timeIntervalSince1970 * 1000.0))])
//Now set this positions array with positions key in params dictionary
let params: Dictionary<String, Any> = ["hash":"asdh832","positions": positions]
let data = try JSONSerialization.data(withJSONObject: params , options: [])
let dataString = String(data: data,encoding: String.Encoding.utf8)!
The Result of print(dataString2) is: [...] which is correct.
No.
You're serialising latitude, longitude and timestamp as strings, while they should be numbers (notice the quotes).
[...] but the now the result after "positions:" looks kinda weird
That's because you double serialise dataString2.
Do not call JSONSerialization.data twice but create one big Dictionary<String, Any> that contains all structured data and then perform the serialisation in one call.
I'm new to coding. I have JSON request which returns different parameters, for example "unitid" and "buldingid".
i want to store the "buldingid" by NSUserDfaults. I use code below for storing it, but every time I get nil response for "buldingid".
reading:
NSUserDefaults.standardUserDefaults().setObject(buildingid, forKey: "buildingidKey")
NSUserDefaults.standardUserDefaults().synchronize()
writing:
let buildingid: [NSString]? = NSUserDefaults.standardUserDefaults().objectForKey("buildingidKey") as? [NSString]
i saved it in a label then stored in NSUserDfaults but it doesn't work (error: Attempt to insert non-property list object)
what should I do to get the correct response for "buldingid"?
Thanks!
I suppose from your code that buildingid is a String, so something like this should work:
NSUserDefaults.standardUserDefaults().setObject(String(buildingid), forKey: "buildingidKey")
NSUserDefaults.standardUserDefaults().synchronize()
Retrieving it should be done like this:
let buildingid = NSUserDefaults.standardUserDefaults().stringForKey("buildingidKey")
I'm using a web API that returns an array of dictionaries. For instance, it returns an array of 9 dictionaries, and inside each dictionary is a key named "title".
I've tried the following code and it crashes with an error of unwrapping an optional value:
for dict in returnedJson {
if let validTitle = dict["title"] as? String {
print(validTitle)
dataList.append(validTitle)
} else {
print("Optional title?")
}
}
The list of titles is printed in the console due to the print(validTitle) line, but the array I'm using to populate the tableview with doesn't seem to want to append it.
I know it's probably something really basic thats eluding me.
Thanks in advance!
You have most likely defined dataList as an implicitly unwrapped optional. That's why you don't need to use optional chaining when calling append on it but if the dataList is nil it would still throw an error since it is trying to unwrap it.
I had the same problem:
1)make sure dataList is a NSMutableArray
2)create a var of type string right before you append
example:
var recs:NSArray = jsonObj.objectForKey("pets")?.objectForKey("records") as! NSArray
for item in recs{
var arr:NSArray = item as! NSArray
var name:String = arr[1] as! String
println(arr[2] as! String)
self.recsAddr.addObject(name)
}
I agree with the others, with that error log I suspect you are using an implicitly unwrapped optional that happen to be nil. We'll need more code for this.
Generally speaking, this kind of problem fits well the Functional Programming Paradigm (so loved by Swift) and can be solved as follow.
let returnedJson : [NSDictionary] = [["title":"one"], ["no title here":""], [:], ["title":"four"], ["title":"five"], ["title":"six"]]
let titles = returnedJson
.map { return $0["title"] } // now we have a list of titles/nil [String?]
.filter { return $0 != nil} // now we have a list of titles (without nil)
.map { return $0! } // now we have this return type [String]
titles // -> ["one", "four", "five", "six"]
Hope this helps.