Swift 3 JSON Bug? - json

I can't seem to compile my code no matter how much I fiddle with it. I think I need another perspective.
At "let image = data["images"] as! [String : AnyObject]"
xcode keeps telling me "Cannot subscript a value of type '[[String : AnyObject]]' with an index of type 'String'"
func retreiveInstagramMedia() {
let token = user?.token
let urlString = "https://api.instagram.com/v1/users/self/media/recent/?access_token=\(token!)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
if let data = json["data"] as? [[String : AnyObject]] {
let image = data["images"] as! [String : AnyObject]
let standardResolution = image["standard_resolution"] as! [String : AnyObject]
let url = standardResolution["url"] as! String
print(url)
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}catch let error as NSError{
print(error)
}
}
}).resume()
}

As Martin said, your data is an array of dictionaries. So iterate through those dictionaries:
if let arrayOfData = json["data"] as? [[String : Any]] {
for individualData in arrayOfData {
if let image = individualData["images"] as? [String : Any],
let standardResolution = image["standard_resolution"] as? [String : Any],
let url = standardResolution["url"] as? String {
// now do something with URL
print(url)
}
}
}
I'd suggest you avoid using ! to force cast/unwrap. When dealing with data from remote sources, you should more gracefully handle situations where one of these subscripts fail to retrieve what you expect they would.

First of all in Swift 3 a JSON dictionary is [String:Any]
Your mistake (developer bug) is to use the array data as the index variable of the loop.
Replace the underscore with anItem and get the image with anItem["images"]
let json = try JSONSerialization.jsonObject(with: data!) as! [String : Any]
if let data = json["data"] as? [[String : Any]] {
for anItem in data {
let image = anItem["images"] as! [String : Any]
let standardResolution = image["standard_resolution"] as! [String : Any]
let url = standardResolution["url"] as! String
print(url)
}
}
Note: The key images implies multiple items so the value could be also an array.

Related

How To Handle json null values in Swift?

My application is crashing while pursing null json
I was tying to solve this issue since long time
you are the best who can assist me with this issue
func downloadJsonWithURLJB() {
let url=URL(string:"http://ccm-hotels.com/RixosJBR/IOS/api/Con4s.php")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["Con+4"] as? [[String : Any]] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
Con4Array.append(Con4s(DateCon4: (aObject["Date"] as? String)!, TimeCon4: (aObject["Time"] as? String)!,GuestNameCon4: (aObject["GuestName"] as? String)!, RoomCon4: (aObject["Room"] as? String)!, LimoCoCon4: (aObject["LimoCo"] as? String)!, DriverCon4: (aObject["Driver"] as? String)!, VehicleCon4: (aObject["Vehicle"] as? String)!, FlightCon4: (aObject["Flight"] as? String)!, PickUpCon4: (aObject["PickUp"] as? String)!, DropToCon4: (aObject["DropTo"] as? String)!, PaxCon4: (aObject["Pax"] as? String)!,TotalCon4: (aObject["Total"] as? String)!, CompleteCon4: (aObject["complete"] as? String)!))
}
}
DispatchQueue.main.async {
self.tableCon4.reloadData()
}
}
catch {}}
The exception
Can't form Range with upperBound < lowerBound
occurs due to the ugly objective-c-ish for loop. If the array is empty the upper bound is -1 which is less than the lower bound.
In Swift never use index based for loops if the index is actually not needed.
Replace
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
with
for aObject in arrJSON {
If you do need the index use the enumerated() syntax
for (index, aObject) in arrJSON.enumerated() {
or the safe half-open range operator
for index in 0..<arrJSON.count {
Other bad practices:
Never load data from a remote URL with synchronous API Data(contentsOf not even on a background thread.
A JSON dictionary in Swift 3+ is [String:Any], never [String:AnyObject].
Variable and property names start with a lowercase letter.
.allowFragments is pointless if the expected type is a collection type.

Get item out of array in Swift

I'm very new to Swift and have spent several hours just trying to pull the photo_url key out of a JSON response.
I'm using this for the reading the JSON:
let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
Then:
if let eventsDictionary = jsonDictionary {
let upcomingEvents = UpcomingEvents(eventsDictionary: eventsDictionary)
completion(upcomingEvents)
} else {
completion(nil)
}
Here is my (failed) attempt to pull out the key:
init(eventsDictionary: [String : Any]) {
//photoUrl = eventsDictionary[EventKeys.photoUrl] as? String
let groups: NSArray = eventsDictionary["groups"] as! NSArray
let url: String = groups[0]
print("THIS IS YOUR RETURNED PHOTO URL--\(url)--END OF RETURNED PHOTO URL")
}
I changed "[String: Any]" to [String: AnyObject] and now i get this...
There are problems casting Any to NSArray. Just make your Init method taking [String:AnyObject]. But, better use Array instead of NSArray here
Try to get url use following code.
let firstObj = groups[0] as! [String: String] // use if let to unwrap is better
let url = firstObj["photo_url"]
To get "photo_url" from the json file in your photo,
it looks like this:
init(eventsDictionary: [String : Any]) {
if let groups = eventsDictionary["groups"] as? [NSDictionary]{
/*
// Get All URL
var urls : [String] = []
for group in groups{
if let url = group.value(forKey: "photo_url"){
urls.append(url)
}
}
*/
// Groups[0] url
let url: String = groups[0].value(forKey: "photo_url") as! String
print("THIS IS YOUR RETURNED PHOTO URL--\(url)--END OF RETURNED PHOTO URL")
}
}
You need to read json as `[String: Any].
if let eventsDictionary = json as? [String: Any] {
let upcomingEvents = UpcomingEvents(eventsDictionary: eventsDictionary)
completion(upcomingEvents)
}
Then, init your UpcomingEvents model like this
init(eventsDictionary: [String : Any]) {
let groups: NSArray = eventsDictionary["groups"] as! NSArray
let group1 = groups[0] as! NSDictionary
let photoURL = group1["photo_url"] as! String
print(photoURL)
}

JSON SWIFT 3 Parsing to s single string Yahoo API

I'm trying to use a Yahoo API to load some stocks but can't do it, please help
func getJSon() {
stockCode = self.stockCodeTextfield.text!
urlString = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes.csv%3Fs%3D" + stockCode + "%26f%3Dsl1d1t1c1ohgv%26e%3D.csv'%20and%20columns%3D'symbol%2Cprice%2Cdate%2Ctime%2Cchange%2Ccol1%2Chigh%2Clow%2Ccol2'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
let url = NSURL(string: urlString)
let data = NSData(contentsOf: url! as URL)
let values = try! JSONSerialization.jsonObject(with: data! as Data, options: .allowFragments) as! NSDictionary
until this
point loads the Json to xcode I think I need to access some keys I'm lost
let maindata = values[0]
let price = maindata["price"]
print(price)
{"query":{"count":1,"created":"2017-05-04T22:24:25Z","lang":"en-US","results":{"row":{"symbol":"TERP","price":"12.30","date":"5/4/2017","time":"4:00pm","change":"-0.12","col1":"12.41","high":"12.51","low":"12.28","col2":"366182"}}}}
Your question is very unclear and vague, but if you are asking how to get to the "results" section of your JSON the simple answer is that you'd do this:
if let query = values["query"] as? [String : Any], let results = query["results"] as? [String : Any], let row = results["row"] as? [String : Any] {
//Now you're inside the "results" dictionary
}
If you need to print the "price" from within "results" you'd do this:
if let query = values["query"] as? [String : Any], let results = query["results"] as? [String : Any], let row = results["row"] as? [String : Any] {
if let row = results["row"] as? [String : Any], let price = row["price"] as? String {
print(price)
}
}

Parsing JSON Data in Swift 3

I am trying to parse JSON data from the Google Civic Information API with Swift 3 and keep running into trouble.
This is the code that I have now for my parseData function:
private func parseData(JSONData: Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String : Any]
if let officials: Any = readableJSON["officials"] as? [String : Any] {
for official in officials as? [String : Any] {
let name = official["name"] as? String
if let address = official["address"] as? [String : String] {
let line1 = address["line1"] as? String
let line2 = address["line2"] as? String
let line3 = address["line3"] as? String
let city = address["city"] as? String
let state = address["state"] as? String
let zipCode = address["zip"] as? String
}
let party = official["party"] as? String
let phones = official["phones"] as? [String: Any]
let urls = official["urls"] as? [String : Any]
let photoURL = official["photoUrl"] as? String
let emails = official["emails"] as? [String : Any]
if let channels = official["channels"] as? [String : Any] {
for j in 0..<channels.count {
let channel = channels[j] as? [String : Any]
let type = channel["type"] as String
let id = channel["type"] as String
}
}
}
}
}
catch { print(error) }
}
Thanks in advance for any help
if let officials: Any = readableJSON["officials"] as? [String : Any] {
for official in officials as? [String : Any] {
You are trying to loop over an object of type Any. Your casting properly on the right side, but then overriding it with a less specific type on the left. You can omit the left side type altogether, as Swift's type inference will know you are getting [String : Any]? from the right side.

How to cast a subscript member to NSArray Swift 3

Returns an error message: Type ‘Any’ has no subscript members in last 2 lines of code. I can^t solve this for NSArray in Swift 3: Any thoughts?
let weatherDictionary: NSDictionary = (try! JSONSerialization.jsonObject(with: dataObject!, options: [])) as! NSDictionary
_ = try JSONSerialization.jsonObject(with: dataObject!, options: .allowFragments) as! [String:Any]
then
struct Weekly{
var dayZeroTemperatureMax: Int
var dayZeroTemperatureMin: Int
init (weatherDictionary: NSDictionary) {
let weeklyWeather = weatherDictionary["daily"] as! NSDictionary
let weeklyForcast = weeklyWeather["data"] as! NSArray
//DAY ZERO
dayZeroTemperatureMax = weeklyForcast[0]["temperatureMax"] as! Int
dayZeroTemperatureMin = weeklyForcast[0]["temperatureMin"] as! Int
}
}
Try changing your code to this :
let weeklyWeather = weatherDictionary["daily"] as! [String: AnyObject]
let weeklyForcast = weeklyWeather["data"] as! [[String: Any]]
in this same project you might need to change this too (in WeatherAlerts) :
init (weatherDictionary: [String: Any]) {
if let weatheralerts = (weatherDictionary["alerts"] as? [[String: Any]]) {
userAlert = weatheralerts[0]["title"] as! String
} else {
userAlert = ""
}
}
I don't really know the reason to change this , if anyone have an explanation please comment here.
but in the same project I had a "fatal error: unexpectedly found nil while unwrapping an Optional value" error here , do you have any idea? what change about URLSessionDownloadTask ?