Ios Swift:使用异步方法获取值

Ios Swift:使用异步方法获取值,ios,swift,asynchronous,reverse-geocoding,clgeocoder,Ios,Swift,Asynchronous,Reverse Geocoding,Clgeocoder,对于这种情况,我正在寻找一两个好的习惯用法: 我想通过异步反向地理定位调用将CLLocationCoordinate2D转换为CLPlacemark,作为其他操作序列的一部分 转换步骤在很大程度上是一个“实用”步骤,因此在处理程序中放入大量代码来执行“其他操作”感觉结构很差 我可以将结果存储在一个类变量中,但我需要知道异步步骤何时完成,这意味着某种类型的事件触发器或主线程的排队超时或其他情况,这看起来也很尴尬 有没有一个标准的方法?将代码放在处理程序中是常见的吗 谢谢 下面是我上下文的特定代码,

对于这种情况,我正在寻找一两个好的习惯用法:

我想通过异步反向地理定位调用将CLLocationCoordinate2D转换为CLPlacemark,作为其他操作序列的一部分

转换步骤在很大程度上是一个“实用”步骤,因此在处理程序中放入大量代码来执行“其他操作”感觉结构很差

我可以将结果存储在一个类变量中,但我需要知道异步步骤何时完成,这意味着某种类型的事件触发器或主线程的排队超时或其他情况,这看起来也很尴尬

有没有一个标准的方法?将代码放在处理程序中是常见的吗

谢谢

下面是我上下文的特定代码,FWIW

func getPlaceFromCoordinate(coordinate: CLLocationCoordinate2D) -> CLPlacemark? {

    var loc = CLLocation(
        latitude: coordinate.latitude,
        longitude: coordinate.longitude
    )

    var mightBeAPlace: CLPlacemark? = nil

    CLGeocoder().reverseGeocodeLocation(loc, completionHandler: {(placemarks, error) -> Void in
        if(error != nil) {
            println("Reverse geocoding error.")
        }
        else if (placemarks.count == 0) {
            println("no placemarks")
        }
        else { // if (placemarks.count > 0)
            println("we have placemarks")
            mightBeAPlace = CLPlacemark(placemark: placemarks[0] as! CLPlacemark)
            println("Inside closure place: \(mightBeAPlace?.locality)")
            lastUserSelectedPlace = mightBeAPlace // This stores it in a class variable.
        }
    })
    println("Outside closure place: \(mightBeAPlace?.locality)")
    return mightBeAPlace // This of course fails because the async task is running separately.
}

典型的方法是自己采用
completionHandler
方法,例如:

lazy var geocoder = CLGeocoder()

func getPlaceFromCoordinate(coordinate: CLLocationCoordinate2D, completionHandler: (CLPlacemark!, NSError?) -> ()) {
    let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

    geocoder.reverseGeocodeLocation(location) { placemarks, error in
        if error != nil {
            println("Reverse geocoding error: \(error)")
        } else if placemarks.count == 0 {
            println("no placemarks")
        }

        completionHandler(placemarks.first as? CLPlacemark, error)
    }
}
你可以这样称呼它:

getPlaceFromCoordinate(coordinate) { placemark, error in 
    if placemark != nil {
        // use placemark here
    }
}

// but do not use it here, because the above runs asynchronously (i.e. later)
就您在这个
completionHandler
闭包中输入了多少代码,以及您在
getplacefromcordinate
中输入了多少代码而言,这完全取决于该代码所包含的内容。但是在
getPlaceFromCoordinate
中重复的常规代码(例如,记录错误,您有什么),并且希望结束仅限于获取
CLPlacemark
和更新模型对象和/或UI

但是,是的,约定是将任何取决于异步方法完成的内容放在完成处理程序中。虽然有一些技术可以使这种异步方法同步运行,但这通常是一个非常糟糕的想法


如果您发现闭包中的代码越来越难处理,那么就进行函数分解,将代码移动到自己的函数中,让完成处理程序简单地调用它。或者还有其他异步模式(例如,异步
NSOperation
子类之间存在依赖关系、承诺/未来等)。但是使用异步模式。

典型的方法是自己采用
completionHandler
方法,例如:

lazy var geocoder = CLGeocoder()

func getPlaceFromCoordinate(coordinate: CLLocationCoordinate2D, completionHandler: (CLPlacemark!, NSError?) -> ()) {
    let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

    geocoder.reverseGeocodeLocation(location) { placemarks, error in
        if error != nil {
            println("Reverse geocoding error: \(error)")
        } else if placemarks.count == 0 {
            println("no placemarks")
        }

        completionHandler(placemarks.first as? CLPlacemark, error)
    }
}
你可以这样称呼它:

getPlaceFromCoordinate(coordinate) { placemark, error in 
    if placemark != nil {
        // use placemark here
    }
}

// but do not use it here, because the above runs asynchronously (i.e. later)
就您在这个
completionHandler
闭包中输入了多少代码,以及您在
getplacefromcordinate
中输入了多少代码而言,这完全取决于该代码所包含的内容。但是在
getPlaceFromCoordinate
中重复的常规代码(例如,记录错误,您有什么),并且希望结束仅限于获取
CLPlacemark
和更新模型对象和/或UI

但是,是的,约定是将任何取决于异步方法完成的内容放在完成处理程序中。虽然有一些技术可以使这种异步方法同步运行,但这通常是一个非常糟糕的想法


如果您发现闭包中的代码越来越难处理,那么就进行函数分解,将代码移动到自己的函数中,让完成处理程序简单地调用它。或者还有其他异步模式(例如,异步
NSOperation
子类之间存在依赖关系、承诺/未来等)。但是使用异步模式。

我决定的方法是编写getPlaceFromCoordinate函数来接受可选的闭包,这样调用方法就可以控制对查找结果的处理

func getPlaceFromCoordinate(
        coordinate: CLLocationCoordinate2D,
        placeAction: ((CLPlacemark) -> Void)?
    ) {

        :
    // Reverse geocode.
        :

    //  If we get a good placemark:
    if (placeAction != nil) {
        placeAction!(placemark)
    }

    }

对于上下文来说,这似乎非常简单、灵活,并将调用代码放回“驾驶座”。不确定还有什么其他的优点或缺点。

我决定的方法是编写getPlaceFromCoordinate函数来接受一个可选的闭包,这样调用方法就可以控制对查找结果的处理

func getPlaceFromCoordinate(
        coordinate: CLLocationCoordinate2D,
        placeAction: ((CLPlacemark) -> Void)?
    ) {

        :
    // Reverse geocode.
        :

    //  If we get a good placemark:
    if (placeAction != nil) {
        placeAction!(placemark)
    }

    }

对于上下文来说,这似乎非常简单、灵活,并将调用代码放回“驾驶座”。不知道还有什么其他的优点或缺点。

谢谢@rob。仍然困扰我的是我可以预见的几个问题。*如果异步位在许多地方使用,我会有一些重复的代码,在同步设置中,我倾向于使用实用函数或其他东西。有关我的解决方案,请参见下面的答案。*如果我有几个异步操作要做,看起来我最终会得到一个嵌套的异步调用链,这既复杂又低效。我相信这是一个标准的习惯用法,如何等待多个异步步骤完成值得提出自己的问题。我不清楚您的答案与我的答案有什么不同(除了使闭包可选),但我想如果您高兴,我也很高兴。仔细看,这是一样的:)这就是我昨晚读这本书的收获,当时我四岁的孩子坐在我的膝盖上看着齐格和沙尔科!:)谢谢@rob。仍然困扰我的是我可以预见的几个问题。*如果异步位在许多地方使用,我会有一些重复的代码,在同步设置中,我倾向于使用实用函数或其他东西。有关我的解决方案,请参见下面的答案。*如果我有几个异步操作要做,看起来我最终会得到一个嵌套的异步调用链,这既复杂又低效。我相信这是一个标准的习惯用法,如何等待多个异步步骤完成值得提出自己的问题。我不清楚您的答案与我的答案有什么不同(除了使闭包可选),但我想如果您高兴,我也很高兴。仔细看,这是一样的:)这就是我昨晚读这本书的收获,当时我四岁的孩子坐在我的膝盖上看着齐格和沙尔科!:)顺便说一句,可选闭包的更简单方法是替换
if placeAction!=nil
和通过简单的可选闭包调用强制展开(例如
placeAction?(placemark)
)。这是一个很好的习惯用法,值得学习。:)我的天真解读是,如果placeAction为零,它将失败,所以这是一个不错的选择