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