Using Swift4, iOS11.1, Xcode9.1,
The following parseData method almost works. Everything seems to work fine (and a correct JSON-data set is fetched by this URLSession and JSONDecode).
However, what is really surprising to me is the fact that a normal Browser shows different JSON-data (i.e. 20x as much is fetched than compared to this iOS-URLSession approach). Why is that ??
In the code below, you can find two print statements. The first showing the actual URLRequest-string (including all query- and type-parameters). The second prints the number of fetched JSON data-sets.
If you use a Browser and fetch the JSON with the exact same URLRequest-string, then the number of datasets is 20 sets. With the URLSession it is only 1 set
Why this difference in JSON data-length delivered ??????????
Here is PRINT_LOG 1 :
https://maps.googleapis.com/maps/api/place/textsearch/json?query=Cham,%20Langackerstrasse&type=bus_station&key=AIzaSyDYtkKiJRuJ9tjkeOtEAuEtTLp5a0XR1M0
(API key no longer valid - after having found the solution, I did change the API-key for security reasons. The Question and its Answer are still of value tough).
Here is PRINT_LOG 2 :
count = 1
Here is my Code:
func parseData(queryString: String) {
// nested function
func createURLWithComponents() -> URL? {
let urlComponents = NSURLComponents()
urlComponents.scheme = "https";
urlComponents.host = "maps.googleapis.com";
urlComponents.path = "/maps/api/place/textsearch/json";
// add params
urlComponents.queryItems = [
URLQueryItem(name: "query", value: "Cham, Langackerstrasse"),
URLQueryItem(name: "type", value: "bus_station"),
URLQueryItem(name: "key", value: AppConstants.GOOGLE_MAPS_DIRECTIONS_API_KEY)
]
return urlComponents.url
}
let myUrl = createURLWithComponents()
var myRequest = URLRequest(url: myUrl!)
myRequest.httpMethod = "GET"
myRequest.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
let myConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: myConfiguration, delegate: nil, delegateQueue: OperationQueue.main)
// Until here everything all right !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// i.e. the following print is correct !!!!!!!!!!!!!!!!!!!!!!!!!
// (and when this print is copied to a Browser then the data fetched has 20 JSON-entries...)
// PRINT_LOG 1
print(myRequest.description)
let myTask = session.dataTask(with: myRequest) { (data, response, error) in
if (error != nil) {
print("Error1 fetching JSON data")
}
else {
do {
//Decode retrived data with JSONDecoder and assing type of Station object
let stationData = try JSONDecoder().decode(Station.self, from: data!)
// Here is the puzzling thing to happen !!!!!!!!!!!!!!!!!!!!!!
// i.e. the following print reveals count = 1 !!!!!!!!!!!!!!!!!
// ??? Why not 20 as with the Browser ????????????????????
// PRINT_LOG 2
print("count = " + "\(String(describing: stationData.results.count))")
}
catch let error {
print(error)
}
}
}
myTask.resume()
}
For completeness, here is the matching Struct:
struct Station: Codable {
let htmlAttributions: [String]
let nextPageToken: String?
let results: [Result]
let status: String
struct Result: Codable {
let formattedAddress: String
let geometry: Geometry
let icon: String
let id: String
let name: String
let photos: [Photo]?
let placeID: String
let rating: Double?
let reference: String
let types: [String]
struct Geometry: Codable {
let location: Coordinates
let viewport: Viewport
struct Coordinates: Codable {
let lat: Double
let lng: Double
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
lat = try values.decode(Double.self, forKey: .lat)
lng = try values.decode(Double.self, forKey: .lng)
}
enum CodingKeys : String, CodingKey {
case lat
case lng
}
}
struct Viewport: Codable {
let northeast: Coordinates
let southwest: Coordinates
enum CodingKeys : String, CodingKey {
case northeast
case southwest
}
}
enum CodingKeys : String, CodingKey {
case location
case viewport
}
}
struct Photo: Codable {
let height: Int
let htmlAttributions: [String]
let photoReference: String?
let width: Int
enum CodingKeys : String, CodingKey {
case height
case htmlAttributions = "html_attributions"
case photoReference = "photo_reference"
case width
}
}
enum CodingKeys : String, CodingKey {
case formattedAddress = "formatted_address"
case geometry
case icon
case id
case name
case photos
case placeID = "place_id"
case rating
case reference
case types
}
}
enum CodingKeys : String, CodingKey {
case htmlAttributions = "html_attributions"
case nextPageToken = "next_page_token"
case results
case status
}
}
Thanks for any help on this.