How to get the JSON data in my app - ios

So , I want to make an app that calls the API of forecast.io to get weather in my app. Someone said me to use SwiftyJSON and Alamofire . I'm new to programming and this is my first app so i dont really know how to do it right. That's my code for now , but I don't know if it is right or not , it works but the call isn't made and I need to enter the JSON data to get the "temperature" data:
// Get Weather
let URL = "https://api.forecast.io/forecast/apikey/\(lat),\(long)"
Alamofire.request(.GET, URL, parameters: nil)
.responseJSON { response in
let jsonData: AnyObject?
do {
jsonData = try NSJSONSerialization.JSONObjectWithData(response.data!, options: [])
} catch {
}
}
It only says that "jsonData" was never used. That's all i wrote for getting the call.

Once you have the jsonData variable, you can use it like a regular NSDictionary by putting the following lines in the do block after the first line
guard let jsonDict = jsonData as? NSDictionary else {return}
If you want to get the current forecast, all you have to do is
guard let currentForecast = jsonDict["currently"] as? NSDictionary else {return}
And then you can get its properties using this link
guard let temperature = currentForecast["apparentTemperature"] as? Int else {return}
All in all, your code should look something like this
let URL = "https://api.forecast.io/forecast/apikey/\(lat),\(long)"
Alamofire.request(.GET, URL, parameters: nil)
.responseJSON { response in
let jsonData: AnyObject?
do {
jsonData = try NSJSONSerialization.JSONObjectWithData(response.data!, options: [])
guard let jsonDict = jsonData as? NSDictionary else {return}
guard let currentForecast = jsonDict["currently"] as? NSDictionary else {return}
guard let temperature = currentForecast["apparentTemperature"] as? Int else {return}
print(temperature)
} catch {
//TODO: Handle errors
}
}
The catch block is to handle errors, so if it could not parse the JSON that's where you would display an alert saying that there was an error.

Related

Working with JSON data retrieving into Swift data types

I'm trying to get data from a URL. It was successful. I can download and convert to a dictionary[String : Any] but response is in nested loops. I don't to how to retrieve. Can someone suggest how to get text and value in the response?
func getDataFromUrl() {
let url = URL(string: "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&departure_time=1408046331&origins=37.407585,-122.145287&destinations=37.482890,-122.150235")
let request = NSMutableURLRequest(url: url!)
let session = URLSession.shared
request.httpMethod = "GET"
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
let destinationAddress = jsonData!["destination_addresses"]
print("Destination address \(String(describing: destinationAddress!))")
let origin_addresses = jsonData!["origin_addresses"]
print("Origin_addresses \(String(describing: origin_addresses!))")
let rows = jsonData!["rows"]
print("Rows \(String(describing: rows!))")
// Here I want to print text and value.
} catch {
// handle error
}
})
dataTask.resume()
}
The above answers work, but in my opinion the more swiftier approach is to use Codable.
class MyResponseType:Codable {
let destination_addresses:String
let rows:[MyCustomRowData]
}
class MyCustomRowData:Codable {
let elements:[MyCustomElementsData]
}
class MyCustomElementsData:Codable {
// properties here
}
Doing this, parsing the json is done like this:
let response = try? JSONDecoder().decode(MyResponseType.self, from: data)
Where the data variable is just the retrieved Data object from the request.
Initially you have to set up some boilerplate code to replicate your expected data format, but working with it is really worth it (and it makes it highly testable).
When the decode succeeds you have a perfectly typed object, it can also have optionals. It just wont decode if fields are missing or of the wrong type (which is a good thing).
Here is the way you can parse text and Value from response:
do{
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
if let destinationAddress = jsonData["destination_addresses"] as? [String] {
print(destinationAddress) //["1 Hacker Way, Menlo Park, CA 94025, USA"]
}
if let origin_addresses = jsonData["origin_addresses"] as? [String] {
print(origin_addresses) //["3251 Hillview Ave, Palo Alto, CA 94304, USA"]
}
if let rows = jsonData["rows"] as? [[String: AnyObject]] {
if rows.indices.contains(0) {
if let elements = rows[0]["elements"] as? [[String: AnyObject]] {
for element in elements {
if let duration = element["duration"] as? [String: AnyObject] {
let text = duration["text"] as? String ?? ""
print(text) //17 mins
let value = duration["value"] as? Int ?? 0
print(value) //1010
}
if let distance = element["distance"] as? [String: AnyObject] {
let text = distance["text"] as? String ?? ""
print(text) //7.2 mi
let value = distance["value"] as? Int ?? 0
print(value) //11555
}
}
}
}
}
}
}catch{ //error handle
}
Use this code:
let rows = jsonData["rows"] as! Array
let element = rows[0] as! Dictionary
let elementArray = element.value(forKey: "elements")
let distance = elementArray[0].value(forKey: "distance")
let text = distance.value(forKey: "text")
print(text)
let value = distance.value(forKey: "value")
print(value)

Swift JSONSerialization as NSDictionary can't get to values inside

JSON Results from output This image should help I am trying to get to [9] "vehicleLocation"
I have an API from UTA that tracks transit data in real-time and displays JSON data
let url = URL(string: "UTA API")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
AlertController.showAlert(_inViewController: self, title: "Error", message: ("Fatal Error"))
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
print(jsonResult)
//get to item within dictionary
let speed = jsonResult["speed"] as? [String:Any]
print(speed)
} catch {
AlertController.showAlert(_inViewController: self, title: "Error", message: "JSON Processing Failed")
}
}
}
}
task.resume()
this returns JSON data:
{
"serviceDelivery": {
"vehicleMonitoringDelivery": {
"vehicleActivity": [
{
"monitoredVehicleJourney": {
"extensions": {
"lastGPSFix": "2017-11-27T23:58:28.083",
"speed": 5.8690799999999994
},
I want the speed value and display in a label. But it comes up nil.
Any ideas and help would be welcomed.
Thanks
Looks like you're trying to access value with key speed at the first level, but it's actually way lower in the hierarchy, beyond a lot of children.
let dic = value[keyPath: "serviceDelivery.vehicleMonitoringDelivery"]
let array = dic["vehicleActivity"] as? NSArray
for speedValueDic in array{
let speed = speedValueDic["speed"] as? String
print(speed)
}
first try to access high level objects then when you reach speed cast it as string not as dictionary this will get you the value
let jsonString = "{\"device\":\"iPhone 6\",\"OS\":\"iOS 9\",\"name\":\"Apple\"}"
let data = jsonString.data(using: .utf8)
let json = try JSONSerialization.jsonObject(with: data!) as? [String : Any]
print (json!["name"] as! String)
var arrVehicleActivity = jsonResult["serviceDelivery"]?["vehicleMonitoringDelivery"]?["vehicleActivity"] as? [Any]
for i in 0..<arrVehicleActivity?.count {
var strSpeed = arrVehicleActivity?[i]?["monitoredVehicleJourney"]?["extensions"]?["speed"] as? String
print("Output should be speed :\(strSpeed)")
}
Hope will helpful to you!!
print("Output should be speed :(strSpeed)")
Output should be speed : 5.8690799999999994

how to save parsed json data into an array with swift 3

So i received some json data from a server now am trying to save it as an array so i can populate a tableview with it but am having a trouble doing it here is my code :
class UserInfo : UIViewController{
var main = ""
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print (response)
}
if let data = data {
let json = (try? JSONSerialization.jsonObject(with: data, options: []))
print(json)
guard let array = json as? [Any] else {return}
for info in array {
guard let infoDict = info as? [String : Any] else{return}
//there is a declared var called main
//main is the one i want save as an array, currently its a variable. i tried to save it as an array by using as! Array but i get error
self.main = infoDict["Title"] as! String
print (self.main)
}
}
}.resume()
}
First you have to declare ary outside of the request scope. Then you have to store your data in the same ary.
var ary: NSMutableArray = NSMutableArray()
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print (response)
}
if let data = data {
let json = (try? JSONSerialization.jsonObject(with: data, options: []))
print(json)
guard let array = json as? [Any] else {return}
for info in array {
guard let infoDict = info as? [String : Any] else{return}
//there is a declared var called main
//main is the one i want save as an array, currently its a variable. i tried to save it as an array by using as! Array but i get error
self.main = infoDict["Title"] as! String
self.ary.add(self.main)
print (self.main)
}
print("Final array is :::",self.ary)
}
}.resume()
Try above code. Hope it will work for you.

I tried to get the 'location' from the below JSON, but it returns response 'nil'

I tried to get the location from the below JSON, but it returns response nil, can you check it once. Below URL gives the response, but I want to display location from below JSON.
let url = URL(string: "http://beta.json-generator.com/api/json/get/4ytNy-Nv7")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil
{
print ("ERROR")
}
else
{
if let content = data
{
do
{
//Array
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
let val = myJson["Location"] as? NSDictionary
print("val=\(val)")
}
catch
{
}
}
}
}
task.resume()
Don't use Foundation datatypes, such as NSDictionary, when they have native Swift counterparts. You also need to cast the JSON to an array of dictionaries. However, the problem that actually caused the issue was that Location is a String and not a dictionary.
guard let myJsonArray = try JSONSerialization.jsonObject(with: content) as? [[String:Any]], let myJson = myJsonArray.first else {return}
print(myJson)
let val = myJson["Location"] as? String
print("val=\(val)")
The root object of the JSON is clearly an array of a dictionary not something (AnyObject). The value for key Location is in the first object of the array
if let myJson = try JSONSerialization.jsonObject(with: content) as? [[String:Any]], !myJson.isEmpty { // check also that the array is not empty
print(myJson)
let val = myJson[0] // get first object of the array
let location = val["Location"] as? String ?? "n/a"
print("location = \(location)")
}
You can use the following function to download your data. Further more since your array has only one object, to access multiple locations you can iterate through the array objects
func downloadData(){
let url = URL(string: "http://beta.json-generator.com/api/json/get/4ytNy-Nv7")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil
{
print ("ERROR")
}
else
{
if let content = data
{
do
{
let myJson = try JSONSerialization.jsonObject(with: content) as? [[String:Any]]
let object = myJson?[0]
if let location = object?["Location"] as? String{
print(location)
}
}
catch
{
}
}
}
}
task.resume()
}
You can change this part :
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
Into :
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as! [AnyHashable: Any]
Then if your JSON only have one object try this to get the Location :
let obj = myJson[0]
let location = obj["Location"] as? String
print("Location \(location)")

Why is the app crashing when it cannot find the song in the itunes API?

I am safely unwrapping, but for some reason the app is still crashing when it cannot find the song equal to the given title. Why is this happening? How can I fix this?
let searchTerm: String = playertitle.text!
let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
let url: NSURL = NSURL(string: urlPath)!
print("Search iTunes API at URL \(url)")
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
do {
if let dict: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
{
let previewUrl = NSURL(string: (dict["results"]![0]["previewUrl"] as? String)!)!
print(previewUrl)
player = AVPlayer(URL: previewUrl)
}
} catch let jsonError as NSError {
}
}
task.resume()
}
}
Guard the response data something like follows,
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
guard data != nil else {
print("response String is nil")
completionHandler(nil, error)
return
}
//completionHandler goes here
}
}
task.resume()
You are safe unwrapping a dictionary and not the results of it. If lets should go one for every possible value. Or take a look at SwiftyJSON framework it allows for lesser if lets.
Don't force unwrap (!) data! It might be nil. Use if let or guard.
if let data = data as? NSData,
let dict: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
While you're at it, check the error parameter too.
When parsing the data, nil might be returned everywhere. So be safe here too. Get rid of all force unwraps.
if let firstResult = dict["results"]?.first as? NSDictionary,
let preview = firstResult["previewUrl"] as? String,
let previewUrl = NSURL(string: preview) {
...
}

Resources