How can I receive a JSON object in the Swift Socket.IO client?
Node.js
From socket.io on Node.js, I emit a json object as in this simplified example:
socket.emit('welcome', { text : 'Hello, World!' });
Swift
In an iOS Swift client, I would like to get this message out of the object.
socket?.on("welcome") {[weak self] data, ack in
print(data)
if let msg = data[0] as? String {
print(msg) // never prints; something's wrong
}
}
The value of data when I print it out is:
[{
text = "Hello, World!";
}]
When I attempt to parse data[0] with the following (from the Apple Developer Blog)...
let json = try? JSONSerialization.jsonObject(with: data[0], options: [])
...I am met with an error message:
Cannot invoke 'jsonObject' with argument list of type '(with: Any, options: [Any])'
Your data is type of [[String: Any]], get text like below.
if let arr = data as? [[String: Any]] {
if let txt = arr[0]["text"] as? String {
print(txt)
}
}
Related
I am fairly new to parsing json data and I am attempting to parse some json data from an rss feed generator and I am running into a problem where I can successfully print the data I am getting but I can't save the data to an object.
I have looked through tutorials that used decodables/codables mostly but I was able to use the urlSession and jsonSerialization objects for what I needed just fine.
class JSONSongs {
// initialize song array...
var songArray: [Song] = []
func getSongs() {
let jsonSongUrl = "https://rss.itunes.apple.com/api/v1/us/apple-music/top-songs/all/50/explicit.json"
let songUrl = URL(string: jsonSongUrl) // convert string to usable url
// start url session task with apple music api url...
// we get some data(hopefully), a response code and an error(hoepfully not)
let songTask = URLSession.shared.dataTask(with: songUrl!) { (data, response, error) in
// checking for an error
if error != nil {
print(Error.self)
print(error?.localizedDescription)
return
} else {
// lets store our data in a variable
if let content = data {
do {
// taking the json data and converting it so we can make objects
let json = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)
//print(json) // making sure data is present
// checking to see if our json data is there
guard let jsonOne = json as? [String: Any] else {
print("invalid operation!")
return
}
// accessing top root of the json file
if let feed = jsonOne["feed"] as? [String: Any] {
//print("it worked") // testing
// accessing the results array where the albums are stored
// there are arrays in the nested json data so we need the double brackets to access them
if let result = feed["results"] as? [[String: Any]]{
for item in result {
// attempting to store data in Song object, this is where problems appear
if let songName = (item["name"] as AnyObject? as? String),
let artistName = (item["artistName"] as AnyObject? as? String),
let coverArt = (item["artworkUrl100"] as AnyObject? as? String),
let artistPage = (item["artistUrl"] as AnyObject? as? String) {
self.songArray.append(Song(songName: songName, artistName: artistName, coverArt: coverArt, artistPage: artistPage))
// printing the data to the console works here but I can't save the data to an object
}
}
}
}
} catch {
print(error.localizedDescription)
print(Error.self)
return
}
}
}
}
songTask.resume()
}
}
All I get is either nil when I try and print a string value or 0 when I try and count the number of objects that are present in the songArray array
Basically your code is correct and should work, however this is a version using Decodable.
The songs property will contain the song data
struct Root : Decodable {
let feed : Feed
}
struct Feed : Decodable {
let results : [Song]
}
struct Song : Decodable {
let name, artistName : String
let artworkUrl100, artistUrl : URL
}
class JSONSongs {
var songs = [Song]()
func getSongs() {
let jsonSongUrl = "https://rss.itunes.apple.com/api/v1/us/apple-music/top-songs/all/50/explicit.json"
let songUrl = URL(string: jsonSongUrl) // convert string to usable url
// start url session task with apple music api url...
// we get some data(hopefully), a response code and an error(hoepfully not)
let songTask = URLSession.shared.dataTask(with: songUrl!) { [weak self] data, _, error in
// checking for an error
if let error = error { print(error); return }
do {
// taking the json data and converting it so we can make objects
let result = try JSONDecoder().decode(Root.self, from: data!)
self?.songs = result.feed.results
print(self?.songs)
} catch {
print(error)
}
}
songTask.resume()
}
}
i am trying to parse JSON data from web service into my Swift
JSON Output on my web browser:
[{"code":0,"message":"Check Username and Password....","userid":""}]
Swift Code:
Alamofire.request(URL_USER_LOGIN, method: .post, parameters: parameters).responseJSON
{
response in
//printing response
print(response)
if let userJSON = response.result.value
{
let userdata:Dictionary = userJSON as! Dictionary<String, Any>
let message:Dictionary = userdata["message"] as! Dictionary<String, Any>
print(message)
}
I want to use message element from the JSON for my code. However i get the following output and error:
(
{
code = 1;
message = "Login Successfull";
userid = 236;
}
)
Could not cast value of type '__NSSingleObjectArrayI' (0x10fd94b98) to 'NSDictionary' (0x10fd958b8).
2018-11-03 20:15:10.762929+0530 testDisplayTable[44610:2871941]
Could not cast value of type '__NSSingleObjectArrayI' (0x10fd94b98) to 'NSDictionary' (0x10fd958b8).
How do I successfully get the value of message and print? Can someone please show me the correct code for my case. Thanks in advance!
It's an array not dictionary
if let userdata = userJSON as? [[String:Any]] {
if let message = userdata[0]["message"] as? String {
print(message)
}
}
I'm using Alamofire to get a data from a JSON file. Example of the output:
[{"image_name":"vacation"},{"image_name":"graduation"}]
I have a problem when I try to access the information from the JSON output.
Alamofire.request(.GET, url).responseJSON { (response) -> Void in
if let JSON = response.result.value {
for json in JSON{
print(json)
}
}
The problem I have is that my JSON output is an AnyObject and I cannt iterate over an AnyObject. If I do the following:
print(JSON[0]["image_name"])
Then I can see the output correctly. How can I iterate over an AnyObject?
You may need to explicitly state the type of JSON as an array of dictionaries:
if let JSON = response.result.value as [[String : AnyObject]] {
// ...
}
I have a API URL that return JSON data, which you can find here https://itunes.apple.com/us/rss/topmovies/limit=25/json
I want to return all of the movie titles in this JSON data.
I am using the SwiftyJSON Framework to parse the JSON data from the URL. I am using a NSURLSession.dataTask to begin the Parse from the URL.
The problem is that the JSON data I want to return is not returning anything.
Here is some code -
JSON Data URL -
let url = "https://itunes.apple.com/us/rss/topmovies/limit=25/json"
Retrieving JSON Data
func getTheJSONData() throws {
let theURL = NSURL(string: url)
let request = NSURLRequest(URL: theURL!)
//let JSONError : NSError?
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
if error == nil{
let swiftyJSON = JSON(data: data!, options: NSJSONReadingOptions.MutableContainers, error: nil)
let Name = swiftyJSON["feed"]["entry"][0]["im:name"]["label"].stringValue
//prints nil..
print(Name)
}
} catch {
// report error
print(error)
}
}
task.resume()
}
Your code does exactly what it's supposed to: it prints the title of a movie.
With this:
let Name = swiftyJSON["feed"]["entry"][0]["im:name"]["label"].stringValue
print(Name)
you get the title of one movie because you're getting the first element of the array with [0].
Since you want to get all movies titles, instead of working with the first element, work with all elements. Example:
let swiftyJSON = JSON(data: data!, options: NSJSONReadingOptions.MutableContainers, error: nil)
let movies = swiftyJSON["feed"]["entry"].arrayValue
let titles = movies.map { $0["im:name"]["label"].stringValue }
print(titles)
print(titles) gives an array of titles:
["Jurassic World", "Avengers: Age of Ultron", "Spy", "Entourage", "Pixels", "Froning", "Pitch Perfect 2", "Cartel Land", "Aladdin", "Furious 7 (Extended Edition)", "Magic Mike XXL", "\'71", "The Age of Adaline", "Cast Away", "Cinderella (2015)", "San Andreas", "Mad Max: Fury Road", "Hotel Transylvania", "Paddington", "Mission: Impossible - Ghost Protocol", "Aloha", "Dope", "Man on Wire", "Me and Earl and the Dying Girl", "The Overnight"]
By the way, as the compiler says with the warning, there's no need to use do catch for JSON() because it doesn't throw.
I'm new to Swift - trying to read a JSON file from a URL. My attempt below.
The JSON looks valid - I tested it with JSONLint but it keeps crashing.
Thoughts?
func getRemoteJsonFile() -> NSDictionary {
//Create a new url
let remoteUrl:NSURL? = NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")
//check if its nil
if let actualRemoteUrl = remoteUrl {
//try to get the data
let filedata:NSData? = NSData(contentsOfURL: actualRemoteUrl)
//check if its nil
if let actualFileData = filedata {
//parse out the dictionaries
let jsonDict = NSJSONSerialization.JSONObjectWithData(actualFileData, options: NSJSONReadingOptions.AllowFragments, error: nil) as NSDictionary
return jsonDict
}
}
return NSDictionary()
}
This took me a second to figure out, so I don't blame you for missing it.
The JSON you linked to is minified, so it's difficult to see the structure. Let's take a look at (a fragment of) it after piping it through a prettifier:
[
{
"PlayerId":2501863,
"PlayerName":"Peyton Manning",
"PlayerTeam":"DEN",
"PlayerPosition":"QB",
"PlayerPassingYards":4727,
"PlayerPassingTDs":39,
"PlayerInterceptions":15,
"PlayerRushingYards":-24,
"PlayerRushingTDs":0,
"PlayerReceivingYards":0,
"PlayerReceivingTDs":0,
"PlayerReturnYards":0,
"PlayerReturnTDs":0,
"PlayerFumbleTDs":0,
"PlayerTwoPointConversions":2,
"PlayerFumblesLost":2,
"PlayerTeamLogo":"http://i.nflcdn.com/static/site/7.0/img/logos/teams-gloss-81x54/den.png"
}
]
Huh. It's encased in brackets, which means that it's an array.
It's an array, so you can't cast it as an NSDictionary. Instead, you could cast it as an NSArray, but why not use native Swift types?
Well, if you don't like types, you're about to find out, but I still think that this is a better way, because it forces you to think about the data you're parsing.
So we have the first part of our type definition for this function; it's an array ([]). What components is our array made up of? We could go with a simple NSDictionary, but we're doing full native types here, so let's use a native Swift dictionary.
To do that, we have to know the types of the dictionary (the syntax for a native dictionary type is [KeyType: ValueType]). Examining the JSON shows that all of the keys are Strings, but the values are of varying types, so we can use AnyObject.
That gives us a dictionary type of [String: AnyObject], and our entire JSON is an array of that, so the final type is [[String: AnyObject]] (wow).
Now that we have the proper type, we can modify the function you're using to parse the JSON a bit.
First of all, let's use our new type for the return and cast values. Then, let's make the return type optional in case something goes wrong and add an error variable to document that.
A cleaned up function would look something like this:
func getData() -> [[String: AnyObject]]? {
let data: NSData? = NSData(contentsOfURL: NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")!)
if let req: NSData = data {
var error: NSError?
if let JSON: [[String: AnyObject]] = NSJSONSerialization.JSONObjectWithData(req, options: NSJSONReadingOptions.AllowFragments, error: &error) as? [[String: AnyObject]] {
return JSON
}
}
return nil
}
That's it!
We can now call the function and extract values from our [[String: AnyObject]] (again, wow) like this:
if let data: [[String: AnyObject]] = getData() {
println(data[0]["PlayerName"]!) // Peyton Manning
}
Update your code with this:
func getRemoteJsonFile() -> [NSDictionary] {
// Create a new URL
let remoteUrl:NSURL? = NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")
let urlString:String = "\(remoteUrl)"
// Check if it's nil
if let actualRemoteUrl = remoteUrl {
// Try to get the data
let fileData:NSData? = NSData(contentsOfURL: actualRemoteUrl)
// Check if it's nil
if let actualFileData = fileData {
// Parse out the dictionaries
let arrayOfDictionaries:[NSDictionary]? = NSJSONSerialization.JSONObjectWithData(actualFileData, options: NSJSONReadingOptions.MutableContainers, error: nil) as [NSDictionary]?
if let actualArrayOfDictionaries = arrayOfDictionaries {
// Successfully parsed out array of dictionaries
return actualArrayOfDictionaries
}
}
}
return [NSDictionary]()
}
This is working fine for me.