I have made a graph request using the FBSDK in my swift application for iphone and I am having some difficulty accessing some of the information it has returned in the result. Specifically I want to get the list of device platforms the user uses. Playing around with the Graph api explorer I get this data for a query on a user's devices.
{
"devices": [
{
"os": "iOS"
}
],
"id": "12345678912345"
}
but in swift the data returned is in this format when I print the graph results value to console:
{
devices = (
{
os = iOS;
}
);
}
so my question is, how do I get the value of 'os' in swift? all my attempts casting the data to NSDictionaries and NSArrays etc have all failed.
let listOfDevices: String = result.valueForKey("devices") as? String
outputs
devices = (
{
os = iOS;
}
);
which just goes to show it doesn't contain any key/pair values for an NSDictionary when I search for ["os"] because of those"()" parenthesis. All help appreciated. Probably something really simple...
I don't want to use string regex.
listOfDevices should be a dictionary.
Swift 2
do {
// Replicating your data for the example
let response = "{\"devices\": [{\"os\": \"iOS\"}],\"id\": \"12345678912345\"}"
// Cast the response as a Dictionary with String as key and AnyObject as value
if let data = response.dataUsingEncoding(NSUTF8StringEncoding),
listOfDevices = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject] {
// Value of `devices` is an array of dictionaries
if let devices = listOfDevices["devices"] as? [[String:AnyObject]] {
for device in devices {
if let os = device["os"] as? String {
print(os)
}
}
}
// Value of `id` is a String
if let id = listOfDevices["id"] as? String {
// use `id`
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
Swift 1
// Replicating your data for the example
let response = "{\"devices\": [{\"os\": \"iOS\"}],\"id\": \"12345678912345\"}"
let data = response.dataUsingEncoding(NSUTF8StringEncoding)
// Cast the response as a Dictionary with String as key and AnyObject as value
let listOfDevices = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! [String:AnyObject]
// Value of `devices` is an array of dictionaries
if let devices = listOfDevices["devices"] as? [[String:AnyObject]] {
for device in devices {
if let os = device["os"] as? String {
println(os)
}
}
}
// Value of `id` is a String
if let id = listOfDevices["id"] as? String {
// use `id`
}
Related
Hi I am currently learning Swift 3, and I have an app I am "developing" to provide weather for a specific location.
I have got my MetOffice API and retrieved the JSON required. I am able to retrieve the location without issue, but when I try to get the temp data I get no result. The temp data is listed as DM in the JSON and is an array within an array within a dictionary within dictionary.
my current code looks like
if let SiteRep = dict["SiteRep"] as? Dictionary<String, Any> {
if let DV = SiteRep["DV"] as? Dictionary<String,Any> {
if let location = DV["Location"] as? Dictionary<String, Any> {
if let period = location["Period"] as? Dictionary<String, Any> {
if let Rep = period["Rep"] as? [Dictionary<String, Any>] {
if let DM = Rep[0]["DM"] as? Double {
self._currentTemp = DM
} } } } } }
relevant vars are declared above this.
I'm not sure how to correct this code to pull this required value back from the JSON
Json as follows, the value i am trying to retrieve is highlighted in bold
{
"SiteRep":{
"Wx":{ },
"DV":{
"dataDate":"2017-02-10T12:00:00Z",
"type":"Forecast",
"Location":{
"i":"350497",
"lat":"99.6115",
"lon":"-21.0017",
"name":"TOWN",
"country":"ENGLAND",
"continent":"EUROPE",
"elevation":"160.0",
"Period":[
{
"type":"Day",
"value":"2017-02-10Z",
"Rep":[
{
"D":"NE",
"Gn":"16",
"Hn":"77",
"PPd":"51",
"S":"9",
"V":"GO",
**"Dm":"2",**
"FDm":"-2",
"W":"24",
"U":"1",
"$":"Day"
},
{
"D":"NNW",
"Gm":"20",
"Hm":"89",
"PPn":"58",
"S":"11",
"V":"GO",
"Nm":"-1",
"FNm":"-6",
"W":"24",
"$":"Night"
}
Here is my JSON data which I am getting from server.
{
"result": "SUCCESS",
"resultcode": "000",
"balance": "-32020",
"available": "-32020",
"reserved": 0
}
When I am trying to parse these JSON data, App crashed and throws Could not cast value of type '__NSCFNumber' (0x1a17dab60) to 'NSString' (0x1a17e5798).
I know the issue is about data type. But when I get Positive value for reserved key in above JSON data, it shows string value in JSON data, but when i get Negative value of reserved key, it return Numeric data type.
Here is the code Which i am reading data.
self.response?.objectForKey("reserved") as! NSString
So How to deal with this kind of issue?
You can parse data using if let statements. Check below
if let reservedNum = JSON["reserved"] as? Double {
print(reservedNum)
} else if let reservedString = JSON["reserved"] as? String {
print(reservedString)
} else {
print("Error Parsing Data")
}
if let safeResult = JSON["result"] as? String {
print(safeResult)
}
And same for the rest and handle the response in a Modal.
What about something like this:
var reserved:Double?
if let reserved_string=response.value(forKey: "reserved") as? NSString{
reserved=reserved_string.integerValue
}
if let reserved_float=response.value(forKey: "reserved") as? Double{
reserved=reserved_float
}
Its because in your json response , reserved key is NSCFNumber type so you can't directly force wrap this into NSString so use this way :
if let mReserved = self.response?.objectForKey("reserved") as? Int {
print(mReserved)
}
You have to check what kind of data type is with Optional.
if self.response?.objectForKey("reserved") as? NSString{
//Do something with NSString
}else if self.response?.objectForKey("reserved") as? NSNumber{
//Do something with NSNumber
}else {
print("Error")
}
Try this below code
let reservedStr = String(response.value(forKey: "reserved") as! Double)
This question already has an answer here:
How to obtain values without key of dictionary?
(1 answer)
Closed 6 years ago.
I am trying to parse JSON files from an url. This JSON has a key that is dynamic, in that it changes per file. Right now my code looks like this:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
// Parsing
if let stations = json["observations"]!!["-10019482"] as? [[String: AnyObject]] {
for observation in stations {
if let name = observation["stationname"] as? String {
if let temperatuuri = observation["Temperature"] as? String {
if let windSpeed = observation["WindSpeedMS"] as? String {
print(name, temperatuuri, windSpeed,"m/s")
self.temperature.text = String(temperatuuri)
}
}
}
}
}
"-10019482" is the part that changed dynamically and the key name cannot be predicted. However, I know that it is always the first key inside "observations".
How would I do the same, but without searching for a specific key name?
Since json["observations"] is a dictionary you could do something like this to obtain it's first key
guard let dict = json["observations"] as? [String: AnyObject],
let firstKey = dict.keys.first else { return }
print(firstKey) // should print the first key found in the observations dictionary
How can I access data from a nested dictionary - when I want to save all data from "CourseDates”? CourseDates = NSArrayM
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
if let test = json[0]["CourseDates"] as? [[String : AnyObject]] {
// heres my problem
}
You can create a function that returns NSDictionary like this:
func parseJSON(data: NSData) -> NSDictionary{
var dic: NSDictionary!
do {
boardsDictionary = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch let error as NSError {
print(error.localizedDescription)
print("Error could not parse JSON data, it's null maybe?!!")
}
//'\(jsonStr)'
return dic
}
UPDATE:
Add This:
public class func jsonToNSData(json: AnyObject) -> NSData?{
return NSJSONSerialization.dataWithJSONObject(json, options: .allZeros, error: nil)
}
let dic = parseJSON(jsonToNSData(YourJsonData)) as! NSDictionary
Hi you can try SwiftyJson, It is a great source through which you can deal with complex JSON in a much more simpler way then you ever thought. For example
{
"metadata":{
"responseInfo":{
"status":200,
"developerMessage":"OK",
}
},
"results":[
{
"title":"Legal immigrants should get freedom before undocumented immigrants – moral, just and fair",
"body":"I am petitioning President Obama's Administration to take a humane view of the plight of legal immigrants. Specifically, legal immigrants in Employment Based (EB) category. I believe, such immigrants were short changed in the recently announced reforms via Executive Action (EA), which was otherwise long due and a welcome announcement.",
"issues":[
{
"id":"28",
"name":"Human Rights"
},
{
"id":"29",
"name":"Immigration"
}
],
"signatureThreshold":100000,
"signatureCount":267,
"signaturesNeeded":99733,
},
{
"title":"National database for police shootings.",
"body":"There is no reliable national data on how many people are shot by police officers each year. In signing this petition, I am urging the President to bring an end to this absence of visibility by creating a federally controlled, publicly accessible database of officer-involved shootings.",
"issues":[
{
"id":"28",
"name":"Human Rights"
}
],
"signatureThreshold":100000,
"signatureCount":17453,
"signaturesNeeded":82547,
}
]
}
From this JSON if you want to extract the result you can do easily like this
func parseJSON(json: JSON) {
for result in json["results"].arrayValue {
let title = result["title"].stringValue
let body = result["body"].stringValue
let sigs = result["signatureCount"].stringValue
let obj = ["title": title, "body": body, "sigs": sigs]
objects.append(obj)
}
}
Here is the simple example how can we extract data from the NSDictionary. And this is simple and i'm not following any standards...
I considered json data in String format.
var data = "{\"data\":{\"fName\":\"naveen\",\"lName\":\"kumar\"},\"friend\":[{\"name\":\"manju\",\"male\":true},{\"name\":\"tanuja\",\"male\":false}]}"
After that you can do
var nsdata = data.dataUsingEncoding(NSUTF16StringEncoding)
if let json = try? NSJSONSerialization.JSONObjectWithData(nsdata!, options: .MutableContainers) as! NSDictionary {
if let some = json["friend"]![0]["name"]! {
print(some) // prints -- manju
}
}
By using the subscipt we can get the data.
Using Xcode 6.4 and programming in swift.
I am typing a program that should read in JSON from a URL. A sample of the JSON can be found at this URL (https://itunes.apple.com/us/rss/topmovies/limit=2/json) and Ive been using this site to parse the JSON in order to read it better (http://json.parser.online.fr/).
Now I need to work through the levels of the JSON in order to get to
the actual movie names and image URL's but I am lost at what kind of variable entryDictionary should be. I was thinking it should be an array of dictionaries, and this compiles, but the output of entryDictionary in the console is sloppy looking, starting with Optionl( and not entry{ as it should. And when I go to loop through entryDictionary, I get an error saying entry does not have a subscript of type AnyObject.
So I am asking how I retrieve the im:name fields and im:image from the JSON.
func downloadDataFromURLString(urlString: String) {
//Downloaded data and is now stored in data. Took code out because
//irrelevant to my problem at this point. Data variable has correct
//JSON, now I am trying to parse it.
} else { //download suceeded, time to parse
var error: NSError? = nil
var names = [String]()
if let rootDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as? [String: AnyObject] {
let feedDictionary = rootDictionary["feed"] as! [String: AnyObject]
let entryDictionary: AnyObject? = feedDictionary["entry"]
println(entryDictionary) //For debugging
//for entry in entryDictionary as! NSArray {
// let name = entryDictionary["name"]
// let image = entryDictionary["image"]
// let movie = Movie(name: name!, image: image!)
// weakSelf!.movies.append(movie)
//}
here is a blueprint of the JSON
"feed":{
"author":{},
"entry":[
{
"im:name":{
"label":"Deadpool"
},
"im:image":[],
"summary":{},
"im:price":{},
"im:contentType":{},
"rights":{},
"title":{},
"link":[],
"id":{},
"im:artist":{},
"category":{},
"im:releaseDate":{}
AnyObject is indeed not subscriptable (you're trying to subscript a variable whose type is AnyObject? with ["feed"]). You should also avoid casting to Cocoa container types like NSArray and NSDictionary whenever you can. Here's an example of how you might get the labels out of the entries array's names array:
import Foundation
func labels(feedDictionary:[String:AnyObject]) -> [String] {
guard let entries = feedDictionary["entry"] as? [String:AnyObject] else {
return []
}
return entries.flatMap { (key:String, value:AnyObject) -> String? in
guard key == "im:name" else {
return nil
}
guard let name = value as? [String:String] else {
return nil
}
return name["label"]
}
}
I'd however advise against using NSJSONSerialization on its own in Swift for anything but the simplest case, as you end up casting and wrapping optionals until the cows come home.
There are good 3rd party libraries such as Freddy and SwiftyJSON which apply Swift language features to accomplish a very convenient JSON (de)serialization experience.
For instance with Freddy you could express your problem in the following style:
let json = try JSON(data: data)
json.decode("feed", type:Feed.self)
struct Feed: JSONDecodable {
let entries:[Entry]
init(json: JSON) throws {
self.entries = try json.arrayOf("entry", type:Entry.self)
}
}
struct Entry:JSONDecodable {
let name:IMName
init(json: JSON) throws {
self.name = try json.decode("im:name", type:IMName.self)
}
}
struct IMName:JSONDecodable {
let label:String
init(json: JSON) throws {
self.label = try json.string("label")
}
}