Converting to Swift 4, ambiguous subscript error - swift

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

Related

Swift : "Value of type 'Any' has no subscripts" error / swift 5

Following code would show that "Value of type 'Any' has no subscripts"
if let postDictionary = jsonDictionary["post"] as? [String: AnyObject]
class FeedController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
if let path = Bundle.main.path(forResource: "single_post", ofType: "json") {
do {
let data = try(NSData(contentsOfFile: path, options: NSData.ReadingOptions.mappedIfSafe))
let jsonDictionary = try(JSONSerialization.jsonObject(with: data as Data, options: .mutableContainers))
if let postDictionary = jsonDictionary["post"] as? [String: AnyObject] {
let post = Post()
post.setValuesForKeysWithDictionary(postDictionary)
self.posts = [post]
}
print(jsonDictionary)
} catch let err {
print(err)
}
}
jsonObject(with:options:) returns Any.
You need to cast it to [String: AnyObject] type first.
Change:
if let postDictionary = jsonDictionary["post"] as? [String: AnyObject]
To:
if let dictionary = jsonDictionary as? [String: AnyObject], let postDictionary = dictionary["post"] as? [String: AnyObject]
Docs:
https://developer.apple.com/documentation/foundation/jsonserialization/1415493-jsonobject

Error while parsing Json in swift 2.3

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

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)

type nsfastenumerationiterator.element aka any has no subscript members

I've updated Xcode from 7 to 8 and Swift from 2.3 to 3.
I'm getting this error at let names = candidate["CandidateName"]!:
type nsfastenumerationiterator.element aka any has no subscript members
let url = URL(string: "https://website.com")
let data = try? Data(contentsOf: url!)
var tmpValues = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
tmpValues = tmpValues.reversed() as NSArray
reloadInputViews()
for candidate in tmpValues {
if ((candidate as? NSDictionary) != nil) {
let names = candidate["CandidateName"]!
//self.values.append(candidate["CandidateName"])
self.values.append(name!)
print(name)
}
}
I think your for in loop should like this. This is work for me. But be sure var tmpValues.
for candidate in (tmpValues as? [[String:Any]])! {
if ((candidate as? NSDictionary) != nil) {
let names = candidate["CandidateName"]! as? String
//self.values.append(candidate["CandidateName"])
self.values.append(name!)
print(name)
}
}

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