Error while parsing Json in swift 2.3 - swift

I am trying to parse this NSDictionary
{"fare":{"value":99.03,"fare_id":"12313545861568689494880005558558852","expires_at":1485864494,"display":"\u20b999.03","currency_code":"INR"},"trip":{"distance_unit":"mile","duration_estimate":720,"distance_estimate":2.76},"pickup_estimate":2}
My code is:
if let statusesArray = try? NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String: Any]],
let user = statusesArray![0]["fare"] as? [String: Any],
let username = user["fare_id"] as? String {
// Finally we got the username
}
else
{
print("DONE")
}
But I am not getting the value fare ID. In fact its printing "DONE" from the else statement. I tried using apple's documentation of handling data,But the same error persist.

Your JSON response is Dictionary not Array, so type cast it to [String:AnyObject] and then get fare_id from the nested fare Dictionary.
if let dict = (try? NSJSONSerialization.JSONObjectWithData(data!, options: [])) as? [String: AnyObject],
let fareDict = dict["fare"] as? [String:AnyObject]
let username = fareDict["fare_id"] as? String {
print(username)
}

Related

Value of type 'NSArray.Element' (aka 'Any') has no subscripts

I openned an old ios project in Xcode with warnings about swift 4 updates.
During some fixing an error I could not find solution.
The error occours while looping jsonArray, passing values to variables...
let url=NSURL(string:"http://webserver.com/json")
let data = NSData(contentsOf: url! as URL)
do {
let jsonResult = try JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
let jsonArray = jsonResult.value(forKey: "person") as! NSArray
for json in jsonArray {
let id = json["id"] as? Int?
let name = json["name"] as? String
let age = json["age"] as? String
tableID.append(String(id!))
tableName.append(name!)
tableAge.append(age!)
tableView.reloadData()
}
} catch {
}
There are many don'ts in the code.
NSURL, NSData
NSArray, NSDictionary (which causes the error)
(NS)Data(contentsOf)
value(forKey:)
.mutableContainers
ignoring the error in the catch block
The actual native Swift syntax is
let url = URL(string:"http://webserver.com/json")!
let task = URLSession.shared.dataTask(with: url) { [unowned self] (data, response, error) in
if let error = error { print(error); return }
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!) as? [String:Any],
let jsonArray = jsonResult["person"] as? [[String:Any]] {
for json in jsonArray {
let id = json["id"] as! Int
let name = json["name"] as! String
let age = json["age"] as! String
self.tableID.append(String(id))
self.tableName.append(name)
self.tableAge.append(age)
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
task.resume()
There is one don't left: Don't use multiple arrays as data source.

Converting to Swift 4, ambiguous subscript error

I am new to swift and currently facing issue at highlighted section of code, the error is Ambiguous use of subscript. I tried other solutions I could find on stackoverflow but could not resolve. Please help me understand the error and its solution.
do{
guard let jsonData = data else {
throw MyError.FoundNil("JSON data issue!")
}
guard let dictionaryData = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String:AnyObject] else {
throw MyError.SerializationError("Unable to serialize")
}
guard let city = dictionaryData["city"]!["name"]!,
// Error on next three lines
let data1 = dictionaryData["list"]![0]! as? [String: AnyObject],
let data2 = dictionaryData["list"]![1]! as? [String: AnyObject],
let data3 = dictionaryData["list"]![2]! as? [String: AnyObject],
let t1 = data1["t"] as? [String: AnyObject],
let t2 = data2["t"] as? [String: AnyObject],
let t3 = data3["t"] as? [String: AnyObject],
let wDay1 = data1["w"]![0]! as? [String:AnyObject],
let wDay2 = data2["w"]![0]! as? [String:AnyObject],
let wDay3 = data3["w"]![0]! as? [String:AnyObject]
else {
throw MyError.DataPopulateError("Mismatch in assigning values from dictionary")
}
First, do not use AnyObject. Define your dictionary as [String: Any].
Next, the problem is once you do something like dictionaryData["some key"] you now have an Any. That needs to be cast to do anything further with it. The error is from trying to use array index access on an Any.
Last, you are misusing the ! operator. The whole point of a guard let is to safely unwrap and safely cast a value. You defeat the whole point by using ! which will crash your app if the data isn't what your code assumes it is.
Update the 2nd guard as:
guard let dictionaryData = try? JSONSerialization.jsonObject(with: jsonData, options: []) as! [String:Any] else {
throw MyError.SerializationError("Unable to serialize")
}
Then rewrite your big guard as follows:
guard let city = (dictionaryData["city"] as? [String:Any])?["name"] as? String,
let list = dictionaryData["list"] as? [[String:Any]], list.count >= 3,
let t1 = list[0]["t"] as? [String:Any],
let t2 = list[1]["t"] as? [String:Any],
let t3 = list[2]["t"] as? [String:Any],
let wDay1 = (list[0]["w"] as? [[String:Any]])?.first,
let wDay2 = (list[1]["w"] as? [[String:Any]])?.first,
let wDay3 = (list[2]["w"] as? [[String:Any]])?.first
else {
throw MyError.DataPopulateError("Mismatch in assigning values from dictionary")
}

Initializer for conditional binding must have Optional type, not '[String : Any]'

Can anyone tell me how to fix this? Im just trying to receive signals from thing speak.
`self.title = "Home"
print("Requesting data...")
Alamofire.request( "https://api.thingspeak.com/channels/290427/feeds.json", parameters: ["results": "1", "location": "false"]) // Gets the latest info from ThingSpeak
.responseJSON { response in
print("Data downloaded: \(response.result)")
if let json = response.result.value as! [String:Any] {
print(json) //see full data
if let feeds = json["feeds"] as? [String: Any] {
for feed in feeds {
print(feed["field2"])
if let temperatureStr = feed["field2"] as? String, let dateStr = feed["created_at"] as? String {
if let temperature = Double(temperatureStr){
self.label.text = "Temperature: \(temperature)°F" //Displays last updated data entry
}
The error is in the line
if let json = response.result.value as! [String:Any] {
Error message says "Initializer for conditional binding must have Optional type, not '[String : Any]'
If you wanna use conditional binding, the right side of the expression should be optional.
Change this:
if let json = response.result.value as! [String:Any]
To this:
if let json = response.result.value as? [String:Any]
That message mean that you need to have optional type so just change
if let json = response.result.value as! [String:Any] {
to
if let json = response.result.value as? [String:Any] {

How to resolve the error "ambiguous reference to member 'subscript'"

I get the error:
Ambiguous reference to member 'subscript'
On the following code:
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
guard let jsonDictionary = jsonObject as? [NSObject: AnyObject],
let photos = jsonDictionary["photos"] as? [String: AnyObject], // this line is giving the error
let photosArray = photos["photo"] as [[String: AnyObject]] else {
print("Error")
}
Previous posts have suggested that I change the type from [String: AnyObject] to [AnyObjectHashable: Any]. This hasn't fixed the error. Can someone explain why this error is occurring and how it can be resolved?
You can replace this, for making dictionary in swift 3 you can use like [String: Any] instead of [String: AnyObject]
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
guard let jsonDictionary = jsonObject as? [String: Any],
let photos = jsonDictionary["photos"] as? [String: AnyObject], // this line is giving the error
let photosArray = photos["photo"] as? [[String: Any]] else {
print("Error")
}
print(jsonDictionary)

Problems with getting values out of nested dictionary in Swift 3 and Xcode 8

I parse JSON with this :
let dictionary = try JSONSerialization.jsonObject(with: geocodingResultsData as Data, options: .mutableContainers)
and get the following nested dictionary as a result
{ response = { GeoObjectCollection = { featureMember =
(
{ GeoObject = { Point = { pos = "40.275713 59.943413"; }; }; },
{ GeoObject = { Point = { pos = "40.273162 59.944292"; }; }; }
);
};
};
}
I'm trying to get the values of coordinates out of this dictionary and save them into new latutudeString and longitudeString variables
Until Xcode 8 GM it worked for me with this code:
if let jsonCoordinatesString: String = dictionary["response"]!!["GeoObjectCollection"]!!["featureMember"]!![0]["GeoObject"]!!["Point"]!!["pos"]!! as? String {
var latLongArray = jsonCoordinatesString.components(separatedBy: " ")
let latitudeString = latLongArray[1]
let longitudeString = latLongArray[0]
}
But since I've installed Xcode 8 GM i receive an error:
Type Any has no Subscript members
How to fix it it Swift 3 with Xcode 8 ? I've read that I can cast it but don't know exactly how to make it work with my nested dictionary in swift 3 with the latest Xcode. I've read can't resolve "Ambiguous use of subscript" but it really did not helped me in my case.
Your JSON data has this type in Swift:
[String: [String: [String: [[String: [String: [String: String]]]]]]]
I would avoid using such a too deeply nested type, but you can write something like this, if you dare use it:
enum MyError: Error {
case invalidStructure
}
do {
guard let dictionary = try JSONSerialization.jsonObject(with: geocodingResultsData as Data, options: .mutableContainers) as? [String: [String: [String: [[String: [String: [String: String]]]]]]] else {
throw MyError.invalidStructure
}
if let jsonCoordinatesString: String = dictionary["response"]?["GeoObjectCollection"]?["featureMember"]?[0]["GeoObject"]?["Point"]?["pos"] {
var latLongArray = jsonCoordinatesString.components(separatedBy: " ")
let latitudeString = latLongArray[1]
let longitudeString = latLongArray[0]
}
} catch let error {
print(error)
}
But you may be hiding some irrelevant members of the JSON data, which might break this as? conversion.
So, you can go step by step, in some cases "need to" in Swift 3, like this:
do {
guard let dictionary = try JSONSerialization.jsonObject(with: geocodingResultsData as Data, options: .mutableContainers) as? [String: AnyObject] else {
throw MyError.invalidStructure
}
if
let response = dictionary["response"] as? [String: AnyObject],
let geoObjectCollection = response["GeoObjectCollection"] as? [String: AnyObject],
let featureMember = geoObjectCollection["featureMember"] as? [[String: AnyObject]],
!featureMember.isEmpty,
let geoObject = featureMember[0]["GeoObject"] as? [String: AnyObject],
let point = geoObject["Point"] as? [String: AnyObject],
let jsonCoordinatesString = point["pos"] as? String
{
var latLongArray = jsonCoordinatesString.components(separatedBy: " ")
let latitudeString = latLongArray[1]
let longitudeString = latLongArray[0]
}
} catch let error {
print(error)
}
(lets are mandatory for each Optional-bindings in Swift 3. And you can change all AnyObjects to Anys, if you prefer.)
The problem is that you have not specify the type of dictionary object, you need to explicitly specify the type of dictionary object as Dictionary like this way.
let dictionary = try JSONSerialization.jsonObject(with: geocodingResultsData as Data, options: .mutableContainers) as! [String: Any]
if let response = dictionary["response"] as? [String: Any],
let geoObjectCollection = response["GeoObjectCollection"] as? [String: Any],
let featureMember = geoObjectCollection["featureMember"] as? [[String: Any]] {
if let geoObject = featureMember[0]["GeoObject"] as? [String: Any],
let point = geoObject["Point"] as? [String: String] {
let latLongArray = point["pos"].components(separatedBy: " ")
let latitudeString = latLongArray[1]
let longitudeString = latLongArray[0]
}
}