Returning object from callback in Swift

2019-01-12 12:06发布

问题:

I want to wrap the geocoder.geocdeAddressString in another method with other logic.

public func placemarkForSearchResult<T>(searchResult: T) -> CLPlacemark? {
        if let searchResult = searchResult as? String {
            let geocoder = CLGeocoder()
            geocoder.geocodeAddressString(searchResult, completionHandler: {
                (placemarks, error) -> Void in

                // Check for returned placemarks
                if let placemarks = placemarks where placemarks.count > 0 {
                    return placemarks[0] as! CLPlacemark // CLPlacemark is not convertible to void error message
                }
                return nil // Typd Void does not conform to protocol NilLiteralConvertible
            })
        }
    }

I have some other logic in this method that's not really relevant, but I was wondering how I can handle a situation like this where I want to return a CLPlacemark, but cannot because the completionHandler for the geocoder returns Void. I cannot change the Void parameter of the geocoder callback. Is that possible? Or am I stuck with calling a delegate method that uses the found CLPlacemark from the geocoder? Thanks in advance.

回答1:

You can never return a placemark from your placemarkForSearchResult function, because obtaining a placemark requires the use of an asynchronous function (geocodeAddressString). By that time that function has finished and calls back into your completion handler, your placemarkForSearchResult has already finished and returned long ago!

You need a strategy compatible with the asynchronous nature of the function you are calling. Instead of returning a placemark from placemarkForSearchResult, you need placemarkForSearchResult to accept a callback function parameter. When you have your placemark in the completion handler, you call that callback function. If that callback function is (cleverly) designed to accept a placemark parameter, you are now handing that placemark to whoever called you in the first place.