简体   繁体   中英

Swift completion handler

I've got a closure calculating distance and time between two points, but I need to extract the array of values (directions and journeyTimes) outside of the closure.

I'm pretty sure a completion handler is the way to go, but not too sure how to implement it.

My code:

var completionHandlers: [() -> Void] = []

@IBAction func calculateItinerary(_ sender: Any) {

    // start calc   

    for index in 0...coordsOfCollective.count - 2 { 

        let sourceLocation = MKPlacemark(coordinate: coordsOfCollective[index]) 

        let destinationLocation = MKPlacemark(coordinate: coordsOfCollective[index + 1])

        let sourceMapItem = MKMapItem(placemark: sourceLocation)
        let destinationMapItem = MKMapItem(placemark: destinationLocation)

        let request = MKDirectionsRequest()
        request.source = sourceMapItem
        request.destination = destinationMapItem

        request.transportType = .automobile
        request.requestsAlternateRoutes = false


        let directions = MKDirections(request: request)

        directions.calculate { response, error in
            if let route = response?.routes.first {
               print("Distance: \(route.distance/1000) km, ETA: \(route.expectedTravelTime/60) mins")

            self.distances.append(route.distance/1000)
            self.journeyTimes.append(route.expectedTravelTime/60)

                print(self.distances)
                print(self.journeyTimes)

                completionHandlers.append(?????)

            } else {
                print("Error!")
            }

        }
    }

print(completionHandlers)

}

The directions.calculate has a declaration of calculate(completionHandler: @escaping MKDirectionsHandler), so I can see it is an escaping closure. But I don't know how I extract distances and journeyTimes arrays outside of it. The print functions currently produce values, but can't be accessed from elsewhere.

Any help is appreciated. Thanks.

var completionHandlers: [() -> Void] = []

for i in 1...10 {

    let handler = {

        print(i)

    }

    completionHandlers.append(handler)

}

After that you can execute the handlers:

completionHandlers[0]()

or, to make the code more expressive:

let handler = completionHandlers[0]
handler()

And to go through all of the handlers:

completionHandlers.forEach { handler in
    handler()
}

Be careful, when you are storing the handler in an array, you have a strong reference to it. Because the closure keeps a strong reference to everything you are referring to within the closure, it's easy to create a reference cycle when you refer to self :

let handler = {
    self.myFunction()
}

You can avoid the retaicnycle by making a weak reference to self:

let handler = { [weak self] in
    self?.myFunction()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM