So the issue I have currently is that the closure is firing before the completion of the request response.
I have implemented a completion handler and closure, I am unsure if I have done this incorrectly or if the method in which I am calling the functions is incorrect.
here is the request containing the completion handler.
func ElevationRequest(listOfPointsToQuery: Array<CLLocationCoordinate2D>, success:Bool,completeHandler: (Bool) -> Void){
var processedQueryPoints = Array<String>() //points which have been ordered based on the execution order are stored here
var newStringCoordinate = String() // the next coordinates are stored here temporarily
var finalStringConvertedCoordinates = String()
var jsonResponse = String()
for i in 0..<listOfPointsToQuery.count{ //go through all listed points to be queried within the http request sent to googles elevation api - returned as a json format dictionary
var latHolder = String(listOfPointsToQuery[i].latitude)
var lonHolder = String(listOfPointsToQuery[i].longitude)
newStringCoordinate = latHolder + "," + lonHolder
processedQueryPoints.append(newStringCoordinate)
}
finalStringConvertedCoordinates = processedQueryPoints.joined(separator: "%7C") //google documentation demonstrates the use of the pipe ("|") - using pipe causes errors and the function will not.. function. "%7C" is used in its place
let apiKey = "AIzaSyAPqcl47sO5eJIkdl46Ww-uJLgv_7aJq3I"
print(finalStringConvertedCoordinates)
struct ElevationResponse: Decodable {
let results: [ElevationResult]
}
struct ElevationResult: Decodable {
let elevation: Double
let location: LatLngLiteral
let resolution: Double?
enum resultKeys: String, CodingKey {
case results = "results"
case elevation = "elevation"
case location = "location"
case resolution = "resolution"
case lat = "lat"
case lon = "lon"
}
}
struct LatLngLiteral: Decodable {
let lat: Double
let lng: Double
}
guard let url = URL(string: "https://maps.googleapis.com/maps/api/elevation/json?&locations=\(finalStringConvertedCoordinates)&key=\(apiKey)") else {
print("Error: cannot create URL")
return
}
// Create the url request
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { [self] data, response, error in
guard error == nil else {
print("Error: error calling GET")
print(error!)
return
}
guard let data = data else {
print("Error: Did not receive data")
return
}
//print("---> data: \(String(data: data, encoding: .utf8))")
guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
print("Error: HTTP request failed")
return
}
do {
guard let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
print("Error: Cannot convert data to JSON object")
return
}
guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: []) else {
print("Error: Cannot convert JSON object to Pretty JSON data")
return
}
guard let prettyPrintedJson = String(data: prettyJsonData, encoding: .utf8)
else {
print("Error: Could print JSON in String")
return
}
//print(prettyPrintedJson)
jsonResponse = prettyPrintedJson
} catch {
print("Error: Trying to convert JSON data to string")
return
}
let decoder = JSONDecoder()
let jrData = jsonResponse.data(using: .utf8)
let jsonResponseProcessed = try! decoder.decode(ElevationResponse.self, from: jrData!)
for i in 0..<listOfPointsToQuery.count{
processedElevation.append(jsonResponseProcessed.results[i].elevation)
print(processedElevation)
print("processed elevation data ^")
}
}
task.resume()
completeHandler(success)
}
the closure is defined right after this function definition like so.
var completehandler:(Bool)->Void = { (sucess) in
if sucess {
print("Complete download data ")
altitudeAdjustmentViaElevationData(elevationPointsList: processedElevation)
} else {
print("Error")
}
}
finally the function is called like so.
ElevationRequest(listOfPointsToQuery: finalAutoPathPoints, success: true, completeHandler: completehandler)
a final note which seems worth mentioning. I am inexperienced so im not sure if this is of any relevance.
I am processing the json response within the same function as the call. The code is included in the first code segment above, the console response looks like this.
Complete download data
[11.59268283843994]
processed elevation data ^
[11.59268283843994, 11.68190288543701]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553, 11.35733222961426]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553, 11.35733222961426, 11.57364559173584]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553, 11.35733222961426, 11.57364559173584, 11.7429027557373]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553, 11.35733222961426, 11.57364559173584, 11.7429027557373, 12.02133083343506]
processed elevation data ^
[11.59268283843994, 11.68190288543701, 11.86490249633789, 11.53255939483643, 11.46291351318359, 11.69645023345947, 11.79109859466553, 11.35733222961426, 11.57364559173584, 11.7429027557373, 12.02133083343506, 11.66207313537598]
processed elevation data ^ ```
credit given to @vidian for their help answering this question.
Regarding the issue of execution prior to completion of the http requests response, this issue was rooted in my miss handling of the completion request.
The tail end of the first code segment is like so.
}
}
task.resume()
completeHandler(success)
}
it should have been structured like this.
}
completeHandler(success)
}
task.resume()
}
another issue within the code I had written was that the closure was not defined correctly. Defining it as a function solved the issue. Correct definition of the closure is below.
func completehandler(_ sucess : Bool) {
if sucess {
print("Complete download data ")
AltitudeAdjustmentViaElevationData(elevationPointsList: processedElevation)
} else {
print("Error")
}
}