http 请求完成处理程序和关闭响应完成之前触发

http request completion handler and closure firing before completion of the response

所以我目前遇到的问题是闭包在请求响应完成之前触发。

我已经实现了一个完成处理程序和闭包,我不确定我是否做错了,或者我调用函数的方法是否不正确。

这里是包含完成处理程序的请求。

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)
    } 

闭包是在这个函数定义之后定义的,就像这样。

var completehandler:(Bool)->Void = { (sucess) in
        if sucess {
            print("Complete download data ")
                altitudeAdjustmentViaElevationData(elevationPointsList: processedElevation)
        } else {
            print("Error")
        }
        
    }

终于这样调用函数了

ElevationRequest(listOfPointsToQuery: finalAutoPathPoints, success: true, completeHandler: completehandler) 

最后一点似乎值得一提。我没有经验,所以我不确定这是否有任何相关性。

我在与调用相同的函数内处理 json 响应。代码包含在上面的第一个代码段中,控制台响应如下所示。

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 ^ ```

感谢@vidian 帮助回答了这个问题。

关于在http请求响应完成之前执行的问题,这个问题的根源在于我对完成请求的处理不当。

第一个代码段的尾端是这样的

       }
            }
        task.resume()
        completeHandler(success)
    }  

它应该是这样构造的。

       }
       completeHandler(success)
            }
        task.resume()
    } 

我编写的代码中的另一个问题是闭包定义不正确。将其定义为函数解决了这个问题。闭包的正确定义如下。

 func completehandler(_ sucess : Bool) {
        if sucess {
            print("Complete download data ")
               AltitudeAdjustmentViaElevationData(elevationPointsList: processedElevation)
        } else {
            print("Error")
        }
        
    }