Parsing JSON Data in Swift 3 - json

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.

Related

Read Json in swift

Hi the question is i want to read the rows in this JSON is an Array, data is the headboard
>data: {..}
>rows [..]
-dataA: "Hi"
-dataB: "Hello"
im using :
if let json = try? JSONSerialization.jsonObject(with: data, options: []) {
if let information = json as? [String : Any]{
let data = information["data"] as? [String : Any]
let rowsN = information["rows"] as? [[String : Any]]
for datab in rowsN{
let dataA = datab ["dataA"] as? String ?? ""
let dataB = datab ["dataB"] as? String ?? ""
print(dataA, dataB)
}
Why is not working?, i think is cause rows is not a headboard, in that case , How could I do it?
let rowsN = information["rows"] as? [[String : Any]] - seems to be the buggy line of code.
As per your example, rows are within data. So you should be trying data["rows"] and not information["rows"].
let rowsN = data["rows"] as? [[String : Any]]
Hope this clarifies
let str = """
{
"data": {
"rows": [
{"dataA": "Hi"},
{"dataB": "Hello"}
]
}
}
"""
let data = Data(str.utf8)
if let json = try? JSONSerialization.jsonObject(with: data, options: []) {
if let information = json as? [String : Any] {
if let data = information["data"] as? [String : Any] {
if let rowsN = data["rows"] as? [[String : Any]] {
for datab in rowsN {
let dataA = datab ["dataA"] as? String ?? ""
let dataB = datab ["dataB"] as? String ?? ""
print(dataA)
print(dataB)
}
} else {
print("could not load rows")
}
} else {
print("could not load data")
}
} else {
print("could not load json as map")
}
} else {
print("could not load json as map")
}
I personally would use a Model class and use JSON Decoder in swift for this. The API you are using is the older Objective C based one.

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

Swift 3 JSON Bug?

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.

Type "Any" has no subscript members while parsing JSON

func parseResponseData(response: AnyObject) {
if let feedData = response["feed"] as? [String: Any]{
let entryArray = feedData["entry"] as Any
if let entry = entryArray as? [Any]{
for object in entry{
print(object)
let appName = object["category"] as [String: Any] // Error: Type "Any" has no subscript members.
}
}
}
}
I am not able to parse the response because of this error, any clue how to resolve this.
JSON response
try this, entryArray is an array of String : Any
func parseResponseData(response: AnyObject) {
if let feedData = response["feed"] as? [String: Any]{
let entryArray = feedData["entry"] as Any
if let entry = entryArray as? [[String: Any]] {
for object in entry {
print(object)
let appName = object["category"] as? [String: Any]
}
}
}
}
You have to tell the compiler the actual types of all subscripted collection types, Any is not sufficient.
It's helpful to use a type alias for the JSON dictionary
typealias JSONDictionary = [String:Any]
func parseResponseData(response: Any) {
if let feedData = response["feed"] as? JSONDictionary,
let entryArray = feedData["entry"] as? [JSONDictionary] {
for object in entryArray {
print(object)
if let category = object["category"] as? JSONDictionary {
print(category)
}
}
}
}

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