Getting All the values of this output json - json

I want to extract the names of these coffes this is an extract of my output because i have like 1000 names, and i want to take them all automatically :
results = (
{
geometry = {
location = {
lat = "-33.3979227";
lng = "-70.58503859999999";
};
viewport = {
northeast = {
lat = "-33.39783990000001";
lng = "-70.58502229999999";
};
southwest = {
lat = "-33.39795669999999";
lng = "-70.58507830000001";
};
};
};
id = 46354da06de96a36c5c44a5fa05a10f8f83f8edd;
name = "Hotel Bidasoa";
"opening_hours" = {
"open_now" = 1;
"weekday_text" = (
);
};
}
);
"place_id" = ChIJ4dfUCC7PYpYRRDkSNifrfBE;
rating = "4.7";
scope = GOOGLE;
types = (
cafe,
lodging,
food,
store,
"point_of_interest",
establishment
);
vicinity = "Avenida Vitacura 4873, Santiago, Santiago";
},
{
geometry = {
location = {
lat = "-33.37900460000001";
lng = "-70.55533029999999";
};
viewport = {
northeast = {
lat = "-33.37897230000002";
lng = "-70.5553148";
};
southwest = {
lat = "-33.37910149999999";
lng = "-70.55537679999999";
};
};
};
id = c451d2146b7a065fa1afd0ffa39353a4b1cae178;
name = "Ceibo Emporio Cafeter\U00eda";
"opening_hours" = {
"open_now" = 0;
"weekday_text" = (
);
};
and thi is my code, but only prints me the first name i want both because i have like 1000 names:
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print (jsonResult)
if let nombre = ((jsonResult["results"]as?NSArray)?[0]as?NSDictionary)?["name"] {
print (nombre)
}

As always:
Never use NSDictionary / NSArray in Swift when parsing JSON.
Never use mutableContainers in Swift. It's completely useless.
To get all items in the results array use a loop, for convenience and readability use a type alias:
typealias JSONDictionary = [String:Any]
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? JSONDictionary {
print (jsonResult)
if let results = jsonResult["results"] as? [JSONDictionary] {
for result in results {
print(result["name"] as? String ?? "n/a")
if let geometry = result["geometry"] as? JSONDictionary,
let location = geometry["location"] as? JSONDictionary {
let lat = location["lat"] as? Double ?? 0.0
let lng = location["lng"] as? Double ?? 0.0
print("latitude: \(lat)")
print("longitude: \(lng)")
}
}
}
}

Related

How to Decode Badly Formatted JSON in Swift using Codable

I am trying to decode the Yelp REST API business search response in Swift using codable. I have managed to decode this using the traditional method of serializing the response into a NSDictionary and just marshaling objects using values from the dictionary; however, as an exercise to myself I am trying to refactor the code to use the Codable protocols and JSONDecoder() in Swift. Yelp really wrote a shitty API and this is the response that I need to decode:
{
businesses = (
{
alias = "dos-caminos-new-york-7";
categories = (
{
alias = mexican;
title = Mexican;
},
{
alias = bars;
title = Bars;
}
);
coordinates = {
latitude = "40.7593727";
longitude = "-73.9853281";
};
"display_phone" = "(212) 918-1330";
distance = "55.57057440108928";
id = 2iwT3iutZvmqzmu7oOkWFw;
"image_url" = "https://s3-media2.fl.yelpcdn.com/bphoto/eHvXPqv6iLcTXfT486z6JA/o.jpg";
"is_closed" = 0;
location = {
address1 = "1567 Broadway";
address2 = "";
address3 = "";
city = "New York";
country = US;
"display_address" = (
"1567 Broadway",
"New York, NY 10036"
);
state = NY;
"zip_code" = 10036;
};
name = "Dos Caminos";
phone = "+12129181330";
price = "$$";
rating = "3.5";
"review_count" = 644;
transactions = (
delivery,
pickup
);
url = "https://www.yelp.com/biz/dos-caminos-new-york-7?adjust_creative=RzPd81IBxDPwaWBeNhRk8w&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=RzPd81IBxDPwaWBeNhRk8w";
},
{
alias = "bond-45-new-york-2";
categories = (
{
alias = italian;
title = Italian;
},
{
alias = pizza;
title = Pizza;
},
{
alias = newamerican;
title = "American (New)";
}
);
coordinates = {
latitude = "40.7591637016814";
longitude = "-73.9859788257256";
};
"display_phone" = "(212) 869-4545";
distance = "77.44246334243893";
id = "8-Ug0Zjs5sL6MARspRJ7CA";
"image_url" = "https://s3-media2.fl.yelpcdn.com/bphoto/CEfwtx0YtfDGog0hWmQ72A/o.jpg";
"is_closed" = 0;
location = {
address1 = "221 W 46th St";
address2 = "";
address3 = "";
city = "New York";
country = US;
"display_address" = (
"221 W 46th St",
"New York, NY 10036"
);
state = NY;
"zip_code" = 10036;
};
name = "Bond 45";
phone = "+12128694545";
price = "$$";
rating = "3.5";
"review_count" = 755;
transactions = (
delivery,
pickup
);
url = "https://www.yelp.com/biz/bond-45-new-york-2?adjust_creative=RzPd81IBxDPwaWBeNhRk8w&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=RzPd81IBxDPwaWBeNhRk8w";
}
);
region = {
center = {
latitude = "40.758896";
longitude = "-73.98513";
};
};
total = 5300;
}
The top level object has a value of businesses which has a list? of Businesses that I want to create. I have created the corresponding Swift Codable structs as such:
struct Response: Codable {
var businesses: [Business]
enum CodingKeys: CodingKey {
case businesses
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
// ERROR: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "businesses", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))).
businesses = try values.decode([Business].self, forKey: .businesses)
print("values is \(values.allKeys)")
}
func encode(to encoder: Encoder) throws {
//TODO
}
}
and
struct Business: Codable {
var name: String
var category:
var latitude: Double = 0.0
var longitude: Double = 0.0
var phoneNumber: String = ""
var distance: Double = 0.0
var imageURL: String = ""
var price: Price
var yelpURL: String
enum CodingKeys: String, CodingKey {
case name = "name"
case category = "categories"
case coordinates = "coordinates"
case phoneNumber = "phone"
case distance = "distance"
case imageURL = "image_url"
case price = "price"
case yelpURL = "url"
}
enum CategoryCodingKey: String, CodingKey {
case alias = "alias"
case title = "title"
}
enum CoordinateInfoKeys: String, CodingKey {
case latitude = "latitude"
case longitude = "longitude"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
// TODO, will add more here but the error is not really here
}
func encode(to encoder: Encoder) throws {
}
}
The error that I get when I try to run this code is in a comment in the Response struct above. It seems to me that the YELP API is formatted in such a way that the value for businesses is not a list of objects but some other type that Swift does not recognize. How do I go about using Codable to decode this Response into the Response struct that will hold a list of Businesses? Is this even possible with the way the YELP API has been setup?

tableview store loses reference on ViewDidLoad nested optional unwrapping

I am trying to parse some weather data, and I have ran into an issue. I created a default value in an array that gives the user a dummy location and value in a table view. This value is unwrapped using the same code below that I am trying to use for real data. It works fine for the dummy value and can find the locationStore easily, but when I am loading from the view that has the parsed data, the locationStore is showing as nil in the debugger. I am not sure how to solve this, so any help would be greatly appreciated.
class LocationWeatherViewController: UITableViewController{
var locationStore: LocationStore!
var imageStore: ImageStore!
var newLocation: Location!
var locationCreated : NSMutableArray = NSMutableArray( array: ["Test ", 0, 0.0, 0.0 , 0.0])
override func viewDidLoad() {
super.viewDidLoad()
print(locationCreated.count)
if let locationName = locationCreated[0] as? String {
print(locationName)
if let currentTemp = locationCreated[2] as? Double{
print(currentTemp)
if let zip32 = (locationCreated[1] as? Int){
let zip = Int64(zip32)
print(zip)
if let xCrd = locationCreated[3] as? Double{
print(xCrd)
if let yCrd = locationCreated[4] as? Double{
print(yCrd)
newLocation = locationStore.createLocation(false, location: locationName, currentTemp: currentTemp, zipCode: zip, xCord: xCrd, yCord: yCrd)
if let index = locationStore.allLocations.indexOf(newLocation){
let indexPath = NSIndexPath(forRow: index, inSection: 0)
tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
}
}
}
}
}
}
func createLocation(random: Bool, location: String, currentTemp: Double, zipCode: Int64, xCord: Double, yCord: Double ) -> Location{
if !random{
let newLocation = Location(random: false, locationNme: location, currentTmperature: currentTemp, locationZpCode: zipCode, xCrd: xCord, yCrd: yCord)
allLocations.append(newLocation)
return newLocation
}
LocationStore:
let newLocation = Location(random: true, locationNme: location, currentTmperature: currentTemp, locationZpCode: zipCode, xCrd: xCord, yCrd: yCord)
allLocations.append(newLocation)
return newLocation
}
Location:
init( locationName: String, currentTemperature: Double, locationZipCode: Int64, xCord: Double, yCord: Double){
self.locationName = locationName
self.currentTemperature = currentTemperature
self.locationZipCode = Int64(locationZipCode)
self.xCord = xCord
self.yCord = yCord
self.itemKey = NSUUID().UUIDString
super.init()
}
convenience init( random:Bool = false, locationNme: String, currentTmperature: Double, locationZpCode: Int64, xCrd: Double, yCrd: Double ){
if random {
let locations = ["Louisville", "Gainesville", "Austin", "San Francisco"]
//38.2527, 85.7585
//29.6516, 82.3248
// 30.2672, -97.7431
// 37.7749, -122.4194
let xCords = [38.2527, 29.6516, 30.2672, 37.7749 ]
let yCords = [-85.7585, -82.3248, -97.7431, -122.4194 ]
let zips = [40217, 32608, 77878, 46454]
let temps = [76.0, 101.3, 95.4, 68.5]
var idx = arc4random_uniform(UInt32(locations.count))
let randomLocation = locations[Int(idx)]
let randomLocationxCord = xCords[Int(idx)]
let randomLocationyCord = yCords[Int(idx)]
let randomZip = zips[Int(idx)]
idx = arc4random_uniform(UInt32(temps.count))
let randomTemp = temps[Int(idx)]
self.init ( locationName: randomLocation, currentTemperature: randomTemp, locationZipCode: Int64(randomZip), xCord: randomLocationxCord, yCord: randomLocationyCord)
}
else{
self.init( locationName: locationNme, currentTemperature: currentTmperature, locationZipCode: locationZpCode, xCord: xCrd, yCord: yCrd)
}
}
APIFinder:
func useAPI(zipCode: Int) -> NSArray{
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let locationURL = NSURL( string: "http://api.openweathermap.org/data/2.5/forecast/city?zip=\(zipCode),us&APPID=74b78f4effe729b2a841cb35e3862d85")
let request = NSURLRequest(URL: locationURL!)
let task = session.dataTaskWithRequest(request) {
(data,response, error) -> Void in
if let locationData = data {
if let jsonString = NSString( data:locationData,encoding: NSUTF8StringEncoding){
let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! [String: AnyObject]
if let city = json["city"]{
if let name = city["name"]{
self.locationArray[0] = name!
self.locationArray[1] = zipCode
}
if let coord = city["coord"]{
if let xCord = coord!["lat"]{
self.locationArray[3] = xCord!
}
if let yCord = coord!["lon"]{
self.locationArray[4] = yCord!
}
}
}
if let list = json["list"]{
if let main = list[0]["main"]{
if let temp = main!["temp"]{
self.locationArray[2] = temp!
}
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
}
else if let requestError = error {
print("Error fetching weather data: \(requestError)")
}
else {
print("Unexpected error with request")
}
}
task.resume()
return locationArray
}
Output:
5
Test
0.0
0
0.0
0.0
5
Hartford
295.54
42328
37.45116
-86.909157
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Solved:
The problem was that I needed to pass the LocationStore between the views in the segue. Such a dumb problem once the answer was shown.
Thanks for all of the help and suggestions.

Day Summary from JSON and swift

I am abel to get the current and hourly weather data and based on the following criteria:
viewController:
let dailyWeather = weatherForecast.weekly[0]
let hourlyWeather = weatherForecast.hourly[hour + 4]
let weeklyWeather = weatherForecast.weekly
self.hourlySummaryLabel.text = hourlyWeather.hourlySummary
self.tomorrowSummary.text = dailyWeather.summary
forecast.swift:
struct Forecast {
var currentWeather: CurrentWeather?
var weekly: [DailyWeather] = []
var hourly: [HourlyWeather] = []
init(weatherDictionary: [String: AnyObject]){
if let currentWeatherDictionary = weatherDictionary["currently"] as? [String: AnyObject] {
currentWeather = CurrentWeather(weatherDictionary: currentWeatherDictionary)
}
if let weeklyWeatherArray = weatherDictionary["daily"]?["data"] as? [[String: AnyObject]] {
for dailyWeather in weeklyWeatherArray {
let daily = DailyWeather(dailyWeatherDictionary: dailyWeather)
weekly.append(daily)
}
}
if let hourlyWeatherArray = weatherDictionary["hourly"]?["data"] as? [[String:AnyObject]] {
for hourlyWeather in hourlyWeatherArray {
let hour = HourlyWeather(dailyWeatherDictionary: hourlyWeather)
hourly.append(hour)
}
}
}
}
however, i need to get the full day summary from the following json:
units = si;
}, "hourly": {
data = (
{
{
apparentTemperature = "33.61";
cloudCover = 0;
dewPoint = "12.77";
humidity = "0.27";
icon = "clear-day";
ozone = "279.14";
precipIntensity = 0;
precipProbability = 0;
pressure = "1004.85";
summary = Clear;
temperature = "34.66";
time = 1463464800;
windBearing = 4;
windSpeed = "2.48";
}
);
icon = wind;
summary = "Breezy until this evening."; -----> Need This Summary
is there any way to do it?

Error passing data from JSON Swift into a array

I get a error: "fatal error: unexpectedly found nil while unwrapping an Optional value" when I try to pass the result of the JSON into an array. I think that the problem is when I try to get the geo coordinate: lat and long into my variables.
Please can somebody help me with this issue?
The code for the passing de result of the JSON to an array is:
ViewController.swift
import UIKit
import MapKit
import Alamofire
class ViewController: UIViewController {
var artworks = [Artwork]()
#IBOutlet weak var mapView: MKMapView!
let initialLocation = CLLocation(latitude: 52.370216, longitude: 4.895168)
let regionRadius: CLLocationDistance = 6000
override func viewDidLoad() {
super.viewDidLoad()
centerMapOnLocation(initialLocation)
getData()
mapView.addAnnotations(artworks)
mapView.delegate = self
}
func getData() {
Alamofire.request(.GET , "http://kaart.amsterdam.nl/datasets/datasets-item/t/kunstwerken-in-de-openbare-ruimte/export/json").responseJSON() {
(_, _, json, _) in
println(json)
var json = JSON(json!)
if let appArray = json["features"].array {
for artObject in appArray {
let title = artObject["properties"]["titel"].string
let locationName = artObject["properties"]["titel_key"].string
let discipline = artObject["properties"]["titel_key"].string
let latitude = (artObject["geometry"]["coordinates"].string! as NSString).doubleValue
let longitude = (artObject["geometry"]["coordinates"].string! as NSString).doubleValue
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
var openArt1 = Artwork(title: title!, locationName: locationName!, discipline: discipline!, coordinate: coordinate)
self.artworks.append(openArt1)
self.mapView.addAnnotations(self.artworks)
}
}
}
}
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
the result of the JSON looks like this:
Optional({
features = (
{
geometry = {
coordinates = (
"4.9305202013246",
"52.363277804149"
);
type = Point;
};
properties = {
adres = "";
content = "";
"content_src" = "";
"date_created" = "2015-05-16 00:07:58";
"date_modified" = "<null>";
datum = "2013-10-09 17:15:00";
email = "";
"id_2" = "";
"link_href" = "";
locatie = "POINT(4.93052020132461 52.363277804148602)";
omschrijving = "";
plaats = "";
postcode = "";
published = "";
summary = "";
"summary_type" = "";
telefoonnummer = "";
titel = "101 namen - 136602";
"titel_key" = "101_namen_136602";
title = "";
type = Kunstwerk;
updated = "";
website = "http://www.amsterdam.nl/kunstencultuur/kunst-openbare/kunst-openbare/kunstwerken/amsterdam-stadsdeel-0/dapperbuurt/101-namen-136602/";
};
artObject["geometry"]["coordinates"] is an Array of Doubles, not a String.
If you println the JSON response it could be confusing as you see the Doubles wrapped into quotes (") but it is an array of Doubles nonetheless in the JSON for the "coordinates" key.
UPDATE:
I just checked and they are Doubles:
var err: NSError?
let data = NSData(contentsOfURL: NSURL(string: "http://kaart.amsterdam.nl/datasets/datasets-item/t/kunstwerken-in-de-openbare-ruimte/export/json")!)
let json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.allZeros, error: &err) as! [String:AnyObject]
let features = json["features"] as! [[String:AnyObject]]
let object1 = features[0]
let geo = object1["geometry"]?["coordinates"] as! [Double]
let lat = geo[0] // 4.9305202013246
let lon = geo[1] // 52.363277804149
You just have to access these values with SwiftyJSON like this in your loop:
let coo = artObject["geometry"]["coordinates"].array!
let latitude = coo[0].doubleValue
let longitude = coo[1].doubleValue

Embedded json data in swift three levels

I am having some troubles with some json data. I'm making a weather app and most of the information I parsed works but the weather
this is the council output for the json data as a whole this is the section im having troubles with
the full output of json
{
base = stations;
clouds = {
all = 90;
};
cod = 200;
coord = {
lat = "39.74";
lon = "-104.98";
};
dt = 1427305893;
id = 5419384;
main = {
humidity = 84;
pressure = 1022;
temp = "274.07";
"temp_max" = "275.35";
"temp_min" = "272.15";
};
name = Denver;
rain = {
1h = "0.25";
};
snow = {
1h = "0.17";
};
sys = {
country = US;
id = 532;
message = "0.07829999999999999";
sunrise = 1427288058;
sunset = 1427332632;
type = 1;
};
visibility = 4023;
weather = (
{
description = "light rain";
icon = 10d;
id = 500;
main = Rain;
},
{
description = snow;
icon = 13d;
id = 601;
main = Snow;
},
{
description = fog;
icon = 50d;
id = 741;
main = Fog;
},
{
description = mist;
icon = 50d;
id = 701;
main = Mist;
}
);
wind = {
deg = 20;
gust = "14.9";
speed = "12.9";
};
}
i also have it print the keys
[base, id, dt, snow, main, coord, sys, wind, weather, visibility, clouds, cod, name, rain]
I tried to save it as an array but when I set the arry[0] to a string it crashes
my code for the function
func populateLabels(weatherData: NSData){
var jsonError: NSError?
let json = NSJSONSerialization.JSONObjectWithData(weatherData, options: nil, error: &jsonError) as NSDictionary
println(json)
if let city = json["name"] as? String {
CityName.text = city
}
println(json.allKeys)
if let coord = json["coord"] as? NSDictionary {
if let longi = coord["lon"] as? Double {
long.text = String(format: "%.2f", longi)
}
if let lati = coord["lat"] as? Double {
lat.text = String(format: "%.2f", lati)
}
}
if let main = json["main"] as? NSDictionary {
if let temper = main["temp"] as? Double {
temp.text = String(format: "%.2f", temper)
}
}
If anyone knows how to get to the description that would be awesome
thanks js
I got it.. thanks for the help blacksquare, larme, chirag90
if let tasks = json["weather"] as? NSArray
{
if let task = tasks[0] as? NSDictionary
{
if let taskName = task["description"] as? NSString
{
println(taskName)
}
}
}