Can't resolve "Ambiguous use of subscript" - ios

I'm trying to convert a JSON response (from an NSUrlSession) into an array that I can use.
It's weird, this was working last night. However I now have a build error saying "ambiguous use of subscript".
let url = NSURL(string: "http://192.168.0.8/classes/main.php?fn=dogBoardingGet")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
//var boardings = [String]()
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let theDogs = json[0] as? [[String: AnyObject]] {
for dog in theDogs {
if let ID = dog["ID"] as? String {
print(ID + " Safe")
let thisDog = Dog(name: (dog["Name"] as? String)!, surname: (dog["Surname"] as? String)!, id: (dog["ID"] as? String)!, boarding: true)
let newIndexPath = NSIndexPath(forRow: self.dogs.count, inSection: 0)
self.dogs.append(thisDog)
self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
}
}
}
} catch {
print("error serializing JSON: \(error)")
}
// print(names) // ["Bloxus test", "Manila Test"]
}
task.resume()
The error is on this line: if let theDogs = json[0] as? [[String: AnyObject]] {.
From what I could tell while looking other questions, the error is because of AnyObject, so I tried to change it to [String: String]but I still get the same error.
Can anyone see the cause of this error?
Extra Information
The JSON response being received from the server:
[[{"ID":"47","Name":"Sparky","Surname":"McAllister"}]]

Looks like you are using the NSJSONSerialization, however you don't say what type of object you expect ( [AnyObject] or [String : AnyObject] ). They error you are getting is due to the fact you haven't casted to the json to [AnyObject].
PS: You might consider not using a force unwrap for the data (data!)
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! [AnyObject]

Related

Working with JSON data retrieving into Swift data types

I'm trying to get data from a URL. It was successful. I can download and convert to a dictionary[String : Any] but response is in nested loops. I don't to how to retrieve. Can someone suggest how to get text and value in the response?
func getDataFromUrl() {
let url = URL(string: "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&departure_time=1408046331&origins=37.407585,-122.145287&destinations=37.482890,-122.150235")
let request = NSMutableURLRequest(url: url!)
let session = URLSession.shared
request.httpMethod = "GET"
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
let destinationAddress = jsonData!["destination_addresses"]
print("Destination address \(String(describing: destinationAddress!))")
let origin_addresses = jsonData!["origin_addresses"]
print("Origin_addresses \(String(describing: origin_addresses!))")
let rows = jsonData!["rows"]
print("Rows \(String(describing: rows!))")
// Here I want to print text and value.
} catch {
// handle error
}
})
dataTask.resume()
}
The above answers work, but in my opinion the more swiftier approach is to use Codable.
class MyResponseType:Codable {
let destination_addresses:String
let rows:[MyCustomRowData]
}
class MyCustomRowData:Codable {
let elements:[MyCustomElementsData]
}
class MyCustomElementsData:Codable {
// properties here
}
Doing this, parsing the json is done like this:
let response = try? JSONDecoder().decode(MyResponseType.self, from: data)
Where the data variable is just the retrieved Data object from the request.
Initially you have to set up some boilerplate code to replicate your expected data format, but working with it is really worth it (and it makes it highly testable).
When the decode succeeds you have a perfectly typed object, it can also have optionals. It just wont decode if fields are missing or of the wrong type (which is a good thing).
Here is the way you can parse text and Value from response:
do{
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
if let destinationAddress = jsonData["destination_addresses"] as? [String] {
print(destinationAddress) //["1 Hacker Way, Menlo Park, CA 94025, USA"]
}
if let origin_addresses = jsonData["origin_addresses"] as? [String] {
print(origin_addresses) //["3251 Hillview Ave, Palo Alto, CA 94304, USA"]
}
if let rows = jsonData["rows"] as? [[String: AnyObject]] {
if rows.indices.contains(0) {
if let elements = rows[0]["elements"] as? [[String: AnyObject]] {
for element in elements {
if let duration = element["duration"] as? [String: AnyObject] {
let text = duration["text"] as? String ?? ""
print(text) //17 mins
let value = duration["value"] as? Int ?? 0
print(value) //1010
}
if let distance = element["distance"] as? [String: AnyObject] {
let text = distance["text"] as? String ?? ""
print(text) //7.2 mi
let value = distance["value"] as? Int ?? 0
print(value) //11555
}
}
}
}
}
}
}catch{ //error handle
}
Use this code:
let rows = jsonData["rows"] as! Array
let element = rows[0] as! Dictionary
let elementArray = element.value(forKey: "elements")
let distance = elementArray[0].value(forKey: "distance")
let text = distance.value(forKey: "text")
print(text)
let value = distance.value(forKey: "value")
print(value)

Cannot downcast from 'Any' to a more optional type '[String : AnyObject]?'

I am trying to fetch the json from url. While Serialization json it is giving error?
static func fetchFeatureApp(){
let urlString="http://ebmacs.net/ubereats/Api/all_product?id=1"
let url = URL(string: urlString)!
URLSession.shared.dataTask(with: URLRequest(url: url)){ (data, responce, error) in
if error != nil
{
print(error)
return
}
do{
let json=try (JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) //as! [String:AnyObject]?//as! [AnyObject]?//as! String? //as! [String:AnyObject]//as! [String: Any]
//////////Error here
//let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any] //program is crashing
var appCategories=[AppCategory]()
for dict in json["products"] as! [[String :AnyObject]]{///////Error Here
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
}catch let err{
print(error)
}
}.resume()
}
The class for Json is
class App:NSObject {
var product_id:NSNumber?
var product_name:String?
var product_description:String?
var image_url:String?
var product_price:NSNumber?
var name:String?
}
image description here
At following lines I am getting error:
Error 1:
`let json=try (JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) //as! [String:AnyObject]?//as! [AnyObject]?//as! String? //as! [String:AnyObject]//as! [String: Any]`
Cannot downcast from 'Any' to a more optional type '[String :
AnyObject]?'
Error 2:
for dict in json["products"] as! [[String :AnyObject]]{ /////////////error
Type 'Any' has no subscript members
How to remove these error ?
The recommended way to parse JSON is to unwrap the optional safely with optional bindings.
Please read the JSON. It's very easy. {} represents a dictionary ([String:Any] in Swift), [] an array ([[String:Any]]) and .mutableContainers is nonsense in Swift anyway.
The root object is a dictionary, the value for key products is an array
struct AppCategory {
let id, name, description, url, price : String
}
do {
if let jsonResult = try JSONSerialization.jsonObject(with:data!) as? [String:Any] {
if let products = jsonResult["products"] as? [[String:String]] {
var appCategories = [AppCategory]()
for product in products {
let category = AppCategory(id: product["product_id"] ?? "",
name: product["product_name"] ?? "",
description: product["product_description"] ?? "",
url: product["image_url"] ?? "",
price: product["product_price"] ?? "")
appCategories.append(category)
}
print(appCategories)
}
}
} catch {
print(error)
}
Try this:
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any]
Edit: This would only work if the top level object in your json is actually a dictionary and not an array. Would be helpful if you could post a redacted version of your json response.
This code is working for me with your url.

Value of optional type 'NSDictionary??' not unwrapped

I've been following a tutorial that was playing around with API, specifically the openweathermap api, and I ran into a problem and xCode gives me options to "Fix it with ! and ??", which unfortunately does not fix the issue either.
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
print(jsonResult)
print(jsonResult?["name"])
if let description = ((jsonResult?["weather"] as? NSArray)?[0] as? NSDictionary)?["description"] as? String {
print(description)
}
} catch {
print("JSON Processing Fail")
}
Im getting an error on if let description = ((jsonResult?["weather"] as? NSArray)?[0] as? NSDictionary)?["description"] as? Stringas a Value of optional type 'NSDictionary??' not unwrapped Error.
Simply use Swift's native type Array instead of NSArray.
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [String: Any] {
if let weatherArray = jsonResult["weather"] as? [[String:Any]],
let dic = weatherArray.first, let description = dic["description"] as? String {
print(description)
}
}
} catch {
print("JSON Processing Fail")
}

JSON Parsing & Optionals in Swift 3

So i recently updated to Swift 3/XCode 8 and some of my code went hay-wire. I've read that some syntax changes have been made but I can't seem get this one right.
I make a request to Twitter and get JSON back:
func forLoadStats(completion: (AnyObject?, NSError?) -> Void)
{
var clientError: NSError?
let idString = api.getUserID()
let client = TWTRAPIClient()
let request = client.urlRequest(withMethod: "GET", url: "https://api.twitter.com/1.1/users/show.json", parameters: ["user_id" : 27446437], error: &clientError)
client.sendTwitterRequest(request)
{ (response, data, connectionError) in
if (connectionError == nil)
{
do {
if let json: Any = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [AnyObject]
{
if let json = json, let immage = json?["profile_image_url_https"] as? String
{
//Make ProfilePic edges round
self.profPic.layer.cornerRadius = 42
self.profPic.clipsToBounds = true
//let immage = image["profile_image_url_https"] as String
let _vImageUrl = immage.replacingOccurrences(of: "_normal", with: "")
let urlProfilePic = NSURL(string: _vImageUrl)
let urlPP = NSData(contentsOf: urlProfilePic! as URL)
self.profPic.image = UIImage(data: urlPP! as Data)
let ScrName = json["screen_name"] as! String
self.scrNameLabel.text = "#\(ScrName)"
//Populate Followers Label.text
let flwrVar = json["followers_count"] as! Int
self.followerLbl.text = "\(flwrVar)"
//Populate Following Label.text
let flwngVar = json["friends_count"] as! Int
self.followingLbl.text = "\(flwngVar)"
//Populate Bio
let bio = json["description"] as! String
self.bioLabel.text = "\(bio)"
//created at date
let accountAge = json["created_at"] as! String
self.createdLbl.text = "\(accountAge)"
let tweetCount = json["statuses_count"] as! Int
self.tweetCount.text = "\(tweetCount)"
let likes = json["favourites_count"] as! Int
self.likesCount.text = "\(likes)"
let lists = json["listed_count"] as! Int
self.listedCount.text = "\(lists)"
}
}
}
catch let error
{
print(error)
}
}
}
}
I get an error on the second "If let" statement that says: "initializer for conditional binding must have optional type not 'Any.
Can someone explain why this is?
Your JSON is obviously a dictionary, a JSON dictionary in Swift 3 is [String:Any]
You caused the error by the silly Any annotation (which is supposed to be Any? but is practically nonsensical) because it confuses the compiler.
If you use a do block, try without question mark but use optional binding:
...
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any] {
if let immage = json["profile_image_url_https"] as? String { ...
There are a couple of problems with the syntax. [AnyObject] will not work to use reference items such as json["profile_image_url_https"]. also, you are redeclaring json through let json = json, which makes it a non option in your let immage = json?["profile_image_url_https"] call, so that becomes a problem. This structure does not have any compiler errors
if let json = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
{
if let json = json, let immage = json["profile_image_url_https"] as? String
{
}
}
This does not have any compiler errors.

Can't execute NSURLSession.sharedSession().dataTaskWithURL in Swift

I have a code to get an employee data from php returned Json which is the following :
[{"id":"1","email":"KK","password":"KKK","firstName":"KKK","lastName":"KK","photo":null,"phone":"22","mobile":"2","position":"SS","adminstrator_id":"1","department_id":"1"}]
Code I have try:
func getEmpById (id:String) {
emp = employee()
let myUrl = NSURL(string:"http://localhost/On%20Call%20App/scripts/getEmployee.php?id=\(id)")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(myUrl!, completionHandler: {
(data, response, error) -> Void in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! [[String: AnyObject]]
let dic = json[0]
if let id = dic["id"] , firstName = dic["firstName"] ,lastName = dic["lastName"], mobile = dic["mobile"],phone = dic["phone"],email=dic["email"],pos=dic["position"]{
self.emp.setId(id as! String )
self.emp.setFirstName(firstName as! String)
self.emp.setLastName(lastName as! String)
self.emp.setPhone(phone as! String)
self.emp.setMobile(mobile as! String)
self.emp.setEmail(email as! String)
self.emp.setPosition(pos as! String)
}
} catch {
print(error)
}
})
task.resume()
}
The problem in this line let task = session.dataTaskWithURL(myUrl!, completionHandler:{ when the app reach this line it will directly go to task.resume() without printing any error
Any help to make this work ?
Your response is of Array type not Dictionary
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSArray
let dic = json[0] as! NSDictionary
print(dic.objectForKey("email"))
It is batter if use use Swift array like this.
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! [[String: AnyObject]]
let dic = json[0]
print(dic["email"])

Resources