I had a block of code parsing JSON from the youtube API. The JSON object received is stored in the dictionary and then a sub array of JSON objects items is stored in item. Xcode is giving me an error where it says: "items" is an ambiguous reference to member subscript for JSON and i for item[i].
I read through some posts on stack-overflow addressing similar issues where it said Swift 3 changed the type to [String: AnyObject] but that didn't work for me either.
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! Dictionary<NSObject, AnyObject>
//print(json)
let item: Array<Dictionary<NSObject,AnyObject>> = json["items"] as! Array<Dictionary<NSObject,AnyObject>>
for i in 0 ..< item.count
{
let snippetDict = (item[i] as Dictionary<NSObject, AnyObject>)["snippet"] as! Dictionary<NSObject, AnyObject>
// Initialize a new dictionary and store the data of interest.
var desiredVideoDict = Dictionary<NSObject, AnyObject>()
desiredVideoDict["title"] = snippetDict["title"]
desiredVideoDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<NSObject, AnyObject>)["default"] as! Dictionary<NSObject, AnyObject>)["url"]
desiredVideoDict["videoID"] = (snippetDict["resourceId"] as! Dictionary<NSObject, AnyObject>)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
//self.videosArray.append(desiredPlaylistItemDataDict)
// Reload the tableview.
self.tblVideos.reloadData()
Thank you for your time and help.
The standard JSON dictionary has the type [String:Any] in Swift 3.
I recommend to use a type alias for better legibility.
typealias JSONObject = [String:Any]
Now you can write your code this way (I changed also the for loop syntax)
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! JSONObject
//print(json)
let items = json["items"] as! Array<JSONObject>
for item in items
{
let snippetDict = item["snippet"] as! JSONObject
// Initialize a new dictionary and store the data of interest.
var desiredVideoDict = JSONObject()
desiredVideoDict["title"] = snippetDict["title"]
desiredVideoDict["thumbnail"] = ((snippetDict["thumbnails"] as! JSONObject)["default"] as! JSONObject)["url"]
desiredVideoDict["videoID"] = (snippetDict["resourceId"] as! JSONObject)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
//self.videosArray.append(desiredPlaylistItemDataDict)
// Reload the tableview.
}
self.tblVideos.reloadData()
...
mutableContainers is not needed at all.
This worked for me:
do
{
let json = try JSONSerialization.jsonObject(with: data , options: .mutableContainers) as! Dictionary<String, AnyObject>
//print(json)
let item = json["items"] as! Array<Dictionary<String,AnyObject>>
for i in 0 ..< item.count
{
let snippetDict = item[i]["snippet"] as! Dictionary<String, AnyObject>
// Initialize a new dictionary and store the data of interest.
var desiredVideoDict = Dictionary<String, AnyObject>()
desiredVideoDict["title"] = snippetDict["title"]
desiredVideoDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<String, AnyObject>)["default"] as! Dictionary<String, AnyObject>)["url"]
desiredVideoDict["videoID"] = (snippetDict["resourceId"] as! Dictionary<String, AnyObject>)["videoId"]
// Reload the tableview.
self.tblVideos.reloadData()
}
}catch{
print("parse error")
}
Related
Does anyone know why I get this error?
func parseData(JSONData: Data){
do{
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
if let tracks = readableJSON["tracks"] as? JSONStandard{
if let items = tracks["items"]{
for i in 0..<items.count {
let item = items[i] as! JSONStandard //Here I get the error: Ambiguous use of 'subscript(_:)'
let name = item["name"]
names.append(name)
Change following
if let items = tracks["items"]
To
if let items = tracks["items"] as? [JSONSStandard]
Currently I'm having some problems with this bit of code that is loading data from firebase database into an array. Since this is inside of viewDidLoad I have to empty my array food = [] before loading the data into it, if I don't then it will duplicate all the objects and I will have double duplicates the second time it loads, triple the third time and etc... However this was not a good fix for multiple reasons so what I would like is that it would only add new objects from the database with .childAdded however if I just switch out .value with .childAdded it will crash, I get a Thread 1: signal SIGABRT on this line: let dict = user_snap.value as! [String: String?]. I am pretty new to swift and don't know how to fix this, would really appreciate some help.
let parentRef = Database.database().reference().child("Recipes")
let storage = Storage.storage()
parentRef.observe(.value, with: { snapshot in
if ( snapshot.value is NSNull ) {
// DATA WAS NOT FOUND
print("– – – Data was not found – – –")
} else {
//Clears array so that it does not load duplicates
food = []
// DATA WAS FOUND
for user_child in (snapshot.children) {
let user_snap = user_child as! DataSnapshot
let dict = user_snap.value as! [String: String?]
//Defines variables for labels
let recipeName = dict["Name"] as? String
let recipeDescription = dict["Description"] as? String
let downloadURL = dict["Image"] as? String
let storageRef = storage.reference(forURL: downloadURL!)
storageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) -> Void in
let recipeImage = UIImage(data: data!)
food.append(Element(name: recipeName!, description: recipeDescription!, image: recipeImage!))
self.tableView.reloadData()
}
}
}
})
let dict = user_snap.value as! [String: String?]
Instead of
let dict = snapshot.value as! Dictionary<String, String>
and maybe you can do null test :
let dict = snapshot.value as! Dictionary<String, String>
if let recipeName = dict["Name"] as String!, let recipeDescription = dict["Description"] as String!, let downloadURL = dict["Image"] as String! {
let storageRef = storage.reference(forURL: downloadURL)
storageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) -> Void in
let recipeImage = UIImage(data: data!)
food.append(Element(name: recipeName, description: recipeDescription, image: recipeImage!, downloadURL: downloadURL))
self.tableView.reloadData()
}
}else {
print("Error! Could not decode data")
}
try this. It should work
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let dict = child.value as! Dictionary<String, Any>
//.....
}
I have a json like this:
{"page":1,"totalPage":1,"listContent":[{"bizID":3,"bizName":"SHELL KEMANGGISAN","bizImage":"http//:www.goog#gmail.com","address":"JL KEMANGGISAN UTAMA, JAKARTA, 11480, INDONESIA","ratingAvg":1.0,"distance":14003691},{"bizID":4,"bizName":"SHELL DAAN MOGOT","bizImage":"http//:www.goog#gmail.com","address":"JL DAAN MOGOT KM 11, JAKARTA, 11710","ratingAvg":3.0,"distance":14004238}]}
I try to catch the result like this but error:
do {
let jsonArr = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSArray
print("jsonArr:\(jsonArr)")
for json in jsonArr {
if let results = json["listContent"] as? NSArray {
for result in results {
let person = Bizz()
person.bizID = result["bizID"] as! String
person.bizName = result["bizName"] as! String
person.bizImage = result["bizImage"] as! String
person.address = result["address"] as! String
person.ratingAvg = result["ratingAvg"] as! String
self.businessBizz.append(person)
}
}
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
} catch {
print("Failed to get Content List: \(error)")
}
the error is:
Could not cast value of type '__NSCFString' (0x10756f2c8) to 'NSArray' (0x10756fb88).
the error at this line:
let jsonArr = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSArray
how to repair it? and get listcontent value.
Your JSON is [String: AnyObject] means Dictionary not an array..
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let results = json["listContent"] as? [[String: AnyObject]] {
for result in results {
let person = Bizz()
person.bizID = result["bizID"] as! Int
person.bizName = result["bizName"] as! String
person.bizImage = result["bizImage"] as! String
person.address = result["address"] as! String
person.ratingAvg = result["ratingAvg"] as! Float
self.businessBizz.append(person)
}
}
You should also convert result["ratingAvg"] and result["bizID"] to Int and Float respectively because they are converted to NSNumber upon being parsed.
You can download the playground from here and test that out yourself.
I've downloaded the data below which is in Json format.
{"name":"Shropshire Outage","nc_lead":"John Smith","dma":"11/111","username":"vwaghx1","status":"REOPENED","sapOrder":"12341245","ccsText":"123","nbPropAtRisk":12,"logs":[{"dateTime":"2016-04-07 20:02:42","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":null,"task":"CUSTPOORSUPPLIES","id_log":1489},{"dateTime":"2016-04-07 20:03:35","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":1238768765,"task":"PRESSURELOGGER","id_log":1490},{"dateTime":"2016-04-07 20:04:36","valveStatusChangeDateTime":"2016-04-07 20:02:00","user":"vwaghx1","uid":7692466478,"task":"CUSTSUPPLIESRESTOREDSOME","id_log":1491}],"id_event":601,"region":"Shropshire","trigger":"No Supply Call”,”valveOps":[{"dateTime":"2016-04-07 20:06:12","user":"vwaghx1","uid":7866756788,"x":678666,"y":723325,"description”:”Burst main downstream valve","id_valve_op":523},{"dateTime":"2016-04-07 20:05:31","user":"vwaghx1","uid":5674456470,"x":344534,"y":723433,"description":"Valve to separate both rezones","id_valve_op":522},{"dateTime":"2016-04-14 12:32:00","user":"vwaghx1","uid":1234512345,"x":123123,"y":123123,"description":"test","id_valve_op":541}],"images":[{"name":"After improvement.jpg","dateTimeCreated":"2016-04-08 14:10:30","contentType":"image/jpeg","caption":null,"uuid":null,"fileExtension":"jpeg","id_image":661},...]}
However, when I try to parse it using the code below, I can only access the string values such as "name","nc_lead", "region" etc.
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let nameStr = dict["name"] as? String {
incidentList.valueStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.valueStr = codeStr
}
if let region = dict[“region”] as? String {
incidentList.valueStr = region
}
if let ncLead = dict[“nc_lead”] as? String {
incidentList.valueStr = ncLead
}
I need to access the group values like "logs", "images" and "valveOps", which have their own string values in arrays.
How can I change my code so that I can access the strings as I am now and also load the groups into arrays?
You can try like this way, declare 3 array first.
var logArr: [[String: AnyObject]] = [[String: AnyObject]]()
var imageArr: [[String: AnyObject]] = [[String: AnyObject]]()
var valveArr: [[String: AnyObject]] = [[String: AnyObject]]()
Now use this array where you are getting response
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let nameStr = dict["name"] as? String {
incidentList.valueStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.valueStr = codeStr
}
if let region = dict["region"] as? String {
incidentList.valueStr = region
}
if let ncLead = dict["nc_lead"] as? String {
incidentList.valueStr = ncLead
}
if let logs = dict["logs"] as? [[String: AnyObject]] {
self.logArr = logs
}
if let valveOps = dict["valveOps"] as? [[String: AnyObject]] {
self.valveArr = valveOps
}
if let images = dict["images"] as? [[String: AnyObject]] {
self.imageArr = images
}
I've been trying to get a JSON String to a Dictionary Value, and I can't get it to work, I'm getting an empty value. Before I tried to pull the data I checked that I got the all JSON, so obviously I'm doing something wrong here
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:
NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
var items = [[String:String]()]
var item:AnyObject
var authorDictionary:AnyObject
for var i = 0; i < jsonResult["item"]?.count; i++ {
items.append([String:String]())
item = (jsonResult["items"] as? [[NSObject:AnyObject]])!
items[i]["content"] = item["content"] as? String
items[i]["title"] = item["title"] as? String
items[i]["publishedDate"] = item["published"] as? String
authorDictionary = item["author"] as! NSDictionary
items[i]["author"] = item["displayName"] as? String
}
println(items)
That's what I got as a result:
[[:]]
I am new to JSON, can someone explain me what I should do and what I did wrong?
You can iterate directly over jsonResult["items"] if it has the right type declared (array of dictionaries).
Then inside the loop you have to create a new dictionary each time, fill this dictionary with the data you grab from the JSON response, then you append the new dictionary to your items array of dictionaries:
var items = [[String:String]]()
for item in jsonResult["items"] as! [[String:AnyObject]] {
var newDict = [String:String]()
newDict["content"] = item["content"] as? String
newDict["title"] = item["title"] as? String
newDict["publishedDate"] = item["published"] as? String
newDict["author"] = item["displayName"] as? String
items.append(newDict)
}
As for authorDictionary, since it's a simple dictionary and not an array, if you assign it a value in the loop, it will be overwritten each time and all you'll have in the end is the author from the last object.
Check this out
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
var items = [[String:String]()]
var item:AnyObject
var authorDictionary:AnyObject
for var i = 0; i < jsonResult["items"]!.count; i++
{
items.append([String:String]())
item = (jsonResult["items"] as! [NSDictionary])[i]
items[i]["content"] = item["content"] as! NSString as String
items[i]["title"] = item["title"] as! NSString as String
items[i]["publishedDate"] = item["published"] as! NSString as String
authorDictionary = item["author"] as! NSDictionary
items[i]["author"] = authorDictionary["displayName"] as! NSString as String
}
println(items)