I am trying to parse out data from a NSDictionary but am having trouble. Whenever I try to access this information it prints nil.
NSDictionary:
{
"-LTR7P8PFWHogjlBENiJ" = {
filmid = 335983;
rating = "5.5";
review = Ehh;
};
}
CODE:
let dict = info.value as! NSDictionary
print(dict) //prints about NSDict
print(dict["review"] as? String) //prints nil
What would be the correct method to print "Ehh" from the NSDictionary?
You have outer dictionary wrapper of your searched result, with string key -LTR7P8PFWHogjlBENiJ
So your code currently searches key review in the outer dict.
You can get the review value as below,
typealias JSON = [String: Any]
let dictionary: JSON = [
"-LTR7P8PFWHogjlBENiJ": [
"filmid": 335983,
"rating": "5.5",
"review": "Ehh"
]
]
if let reivew = (dictionary.first?.value as? JSON)?["review"] as? String {
print(reivew)
}
For NSDictionary, you might have to use this as below,
let dict = info.value as! NSDictionary
if let reivew = (dict.allValues.first as? JSON)?["review"] as? String {
print(reivew)
}
Related
I have made a struct that is helping me fetching info from a twitter json. The json has values such as text, which I am able to fetch without a problem, but it also has a dictionary names user and it has the string screen_name inside it.
How can I access that string?
Here is how I access the text string and how I fetch the user dictionary:
func parseTwitterJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let twitterLocations = NSMutableArray()
for i in 0 ..< jsonResult.count{
jsonElement = jsonResult[i] as! NSDictionary
let twitterLocation = twitterLocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let lang = jsonElement["lang"] as? String,
let text = jsonElement["text"] as? String,
let user = jsonElement["user"] as? NSDictionary
{
twitterLocation.lang = lang
twitterLocation.text = text
twitterLocation.user = user
}
twitterLocations.add(twitterLocation)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.twitterDownloaded(items: twitterLocations)
})
}
To access the value of a key from a dictionary you would use
let myDictName : [String:String] = ["keyName" : "value"]
let value = myDictName["keyName"]
//value will be equal to "value"
Since you have the element user as an dictionary, you can just say
let userName = user["screen_name"]
I have the following data I received from Firebase. I have made my snapshotValue a NSDictionary.
self.ref.child("users").child(facebookID_Firebase as! String).observeSingleEvent(of: .value, with: { (snapshot) in
let snapshotValue = snapshot.value as? NSDictionary
print(snapshotValue, "snapshotValue")
//this line of code doesn't work
//self.pictureURL = snapshot["picture"]["data"]["url"]
}) { (error) in
print(error.localizedDescription)
}
I tried How do I manipulate nested dictionaries in Swift, e.g. JSON data? , How to access deeply nested dictionaries in Swift , and other solutions yet no luck.
How do I access the url value inside the data key AND the picture key?
I can make another reference in Firebase and get the value, but I'm trying to save another request. 😓
When you refrence to a key of a Dictionary in swift you get out an unwrapped value. This means it can be nil. You can force unwrap the value or you can use pretty if let =
this should probably work.
if let pictureUrl = snapshot["picture"]["data"]["url"] {
self.pictureURL = pictureUrl
}
Try using :-
if let pictureDict = snapshot.value["picture"] as? [String:AnyObject]{
if let dataDict = pictureDict.value["data"] as? [String:AnyObject]{
self.pictureURL = dataDict.value["url"] as! String
}
}
Inline dictionary unwrapping:
let url = ((snapshot.value as? NSDictionary)?["picture"] as? NSDictionary)?["url"] as? String
You can use the following syntax, that is prettier:
if let pictureDict = snapshot.value["picture"] as? [String:AnyObject],
let dataDict = pictureDict.value["data"] as? [String:AnyObject] {
self.pictureURL = dataDict.value["url"] as! String
}
}
I have parsed the JSON data, now while setting the JSON to my NSDictionary there might be certain keys in the JSON that might not be present. I want to check if the key is present in the JSON parsed to me and if not, set blank field as value to the key in the `NSDictionary' object.
jsonData = ["id": ((json["idnumber"]) as? String!)!,
"Name": ((json["name"]) as? String!)!,
"Roll Number": ((json["rollnumber"]) as? String!)!,
"Class": ((json["class"]) as? String!)!,
"Marks": ((json["marks"]) as? String!)!,
"Gender": ((json["gender"]) as? String!)!]
So in the above case, the marks field may or may not be present in the JSON. I want to check this and assign respective value to the corresponding key in jsonData.
I tried using "??", but it takes lot of compilation time.
You can use if let or guard for conditional optional wrapping for that like this.
var jsonData = [String : String]
if let num = json["idnumber"]) as? String {
jsonData["id"] = num
}
else {
jsonData["id"] = num
}
and so on for others.
Edit: You can also try like this.
var id = name = rollNum = class = ""
if let num = json["idnumber"]) as? String {
id = num
}
if let sname = json["name"]) as? String {
name = sname
}
...
Then at last create Dictionary
var jsonData = ["id": id, "name": name, ...]
You can set the value if present otherwise blank string (""). This will prevent crash. Try below code:-
let idValue = dictionary["idnumber"] as? String ?? ""
let name = dictionary["name"] as? String ?? ""
let rollNumber = dictionary["rollnumber"] as? String ?? ""
let className = dictionary["class"] as? String ?? ""
let marks = dictionary["marks"] as? String ?? ""
let gender = dictionary["gender"] as? String ?? ""
let jsonDic : NSMutableDictionary = NSMutableDictionary()
jsonDic.setObject(idValue, forKey: "id")
jsonDic.setObject(name, forKey: "name")
jsonDic.setObject(className, forKey: "class")
jsonDic.setObject(rollNumber, forKey: "rollNumber")
jsonDic.setObject(marks, forKey: "marks")
jsonDic.setObject(gender, forKey: "gender")
Here goes my code.
func connectionDidFinishLoading(connection: NSURLConnection){
var err: NSError
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
if jsonResult.count>0 && jsonResult["results"]!.count>0 {
var result: NSArray = jsonResult["results"] as! NSArray
println("\(result)")
var dict = NSDictionary()
var myDict = NSDictionary()
for dict in result {
let googleGeo = dict["geometry"] as! NSDictionary
let googleLoc = googleGeo["location"] as! NSDictionary
let latitude = googleLoc["lat"] as! Float
let longitude = googleLoc["lng"] as! Float
let googleicon = dict.valueForKey("icon") as? NSString
let googlename = dict["name"] as? NSString
let googlevicinity = dict["vicinity"] as? NSString
myDict.setValue(latitude, forKey: "lat"
}
}
}
After parsing from Google Places API, i received longitude, latitude, name, vicinity, icon. Now i want to append these value to myDctionary so that i can pass the value to an array and to the next view controller.
Please someone let me know to to do it ?
My friend, you should try this.
Let the dictionary know exactly what type of key/value pairs you want it to hold. You want to use a "String" as the key and since your values have different datatypes you want to use "AnyObject" as the value.
UPDATE For Swift 2 you would use String:AnyObject but for Swift3 you would use String:Any. I've updated the code to show the Swift 3 version instead.
//this says your dictionary will accept key value pairs as String/Any
var myDict = [String:Any]()
You use Any because you have so many different datatypes
//Your values have are being cast as NSDictionary, Float, and NSStrings. All different datatypes
let googleGeo = dict["geometry"] as? NSDictionary
let googleLoc = googleGeo["location"] as? NSDictionary
let latitude = googleLoc["lat"] as? Float
let longitude = googleLoc["lng"] as? Float
let googleicon = dict.valueForKey("icon") as? NSString
let googlename = dict["name"] as? NSString
let googlevicinity = dict["vicinity"] as? NSString
Now you use the method .updateValue(value: Value, forKey: Hashable) to set your keys and values
//update the dictionary with the new values with value-type Any and key-type String
myDict.updateValue(googleGeo, forKey: "geometry")
myDict.updateValue(googleLoc, forKey: "location")
myDict.updateValue(latitude, forKey: "lat")
myDict.updateValue(longitude, forKey: "lng")
myDict.updateValue(googleicon, forKey: "icon")
myDict.updateValue(googlename, forKey: "name")
myDict.updateValue(googlevicinity, forKey: "vicinity")
myDict should now have have all these key/value pairs and you do what you want with them by using the key to extract the value. Btw I only used those key names because for your post it seemed that's the convention you was using. You can name the keys whatever you want. But whatever you name them they have to be the same name you use to extract the value.
Hope this helps!
Having trouble which is probably so minor but my searches turn up nothing. I have a json model as follows :
//quick syntax to give you an idea of the model
{user:
{"name": "",
"password": "",
"medium" : {
{"title":"",
{"description":""}}}
I'm getting the above data model from a GET request to user and it returns all the info above but when i try to parse the "medium" information such as "title" & "description" I'm having no luck. I get these responses in Xcode that say
"Value of object 'AnyObject' not unwrapped, did you mean to use ! or ?"
and then when i click on the round red Xcode message to fix it it places !s and ?s everywhere but the error remains. Here is my parse method which worked perfectly fine when I was parsing only from the "medium". Any idea what I'm doing wrong?
a portion of the parse method where i get the same error for each attribute:
all lines with the same error indicated by *
// Parse JSON data
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String
*media.category = jsonMedia["medium"]["category"] as! String
*media.image = jsonMedia["medium"]["image"] as! String
*if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
Still no luck with anything. I don't understand why it works with regular JSON but Xcode won't accept anything when I try to obtain nested. All of your help has been appreciated. In the meantime here's the full method if it helps any further
func parseJsonData(data: NSData) -> [Media] {
var medium = [Media]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonMedium = jsonResult?["media"] as! [AnyObject]
for jsonMedia in jsonMedium {
let media = Media()
media.title = jsonMedia["medium"]["title"] as! String
media.description = jsonMedia["medium"]["description"] as! String
media.category = jsonMedia["medium"]["category"] as! String
media.image = jsonMedia["medium"]["image"] as! String
if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
medium.append(media)
}
} catch {
print(error)
}
return medium
}
let json = [
"user" : [
"name" : "My Name",
"password" : "My Password",
"medium" : [
"title" : "My Title",
"description" : "My Description"
]
]
]
if let userJson = json["user"] as? [String : AnyObject] {
if let name = userJson["name"] as? String {
print("name: \(name)")
}
if let password = userJson["password"] as? String {
print("password: \(password)")
}
if let mediumJson = userJson["medium"] as? [String : AnyObject] {
if let title = mediumJson["title"] as? String {
print("title: \(title)")
}
if let description = mediumJson["description"] as? String {
print("description: \(description)")
}
}
}
Maybe it helps
let request : ASIFormDataRequest = ...your request
if request.responseString() != nil {
var jsonResponse : Dictionary<String, AnyObject>?
do{
jsonResponse = try NSJSONSerialization.JSONObjectWithData(request.responseData(), options: NSJSONReadingOptions.AllowFragments) as? Dictionary<String, AnyObject>
} catch _ {
//some error
}
}
FIXED IT! Took an entire day of deep thought and google/youtube/stack/brainstorming and your help but it was one changed line that got the whole thing going
// Parse JSON data
let jsonMedium = jsonResult?["user"]!["medium"] as? [AnyObject]
for jsonMedia in jsonMedium! {
let media = Media()
media.title = jsonMedia["title"] as! String
media.description = jsonMedia["description"] as! String
instead of :
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String