Swift:使用异步方法获取值
Swift: get value using async method
我正在为这种情况寻找一两个好的成语:
我想通过异步反向地理定位调用将 CLLocationCoordinate2D 转换为 CLPlacemark,作为其他操作序列的一部分。
转换步骤是一个非常重要的 "utility" 步骤,因此在处理程序中放置大量代码来执行 "other operations" 感觉结构很差。
我可以将结果存储在 class 变量中,但是我需要知道异步步骤何时完成,这意味着某种事件触发或主线程排队超时或其他,这也显得别扭。
对此有标准的方法吗?将代码放在处理程序中是否很常见?
谢谢!
这是我的上下文的具体代码,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
闭包中放入了多少代码,以及在 getPlaceFromCoordinate
中放入了多少代码,这完全取决于该代码所包含的内容。但是在 getPlaceFromCoordinate
中重复了很多例行代码(例如记录错误,你有什么),希望闭包将仅限于获取 CLPlacemark
和更新模型对象 and/or UI.
但是,是的,约定是在完成处理程序中放置任何取决于异步方法完成的内容。虽然有一些技术可以使这种异步方法同步运行,但这通常是一个非常糟糕的主意。
如果您发现闭包内的代码变得笨拙,则进行功能分解并将此代码移动到它自己的函数中,让完成处理程序简单地调用它。或者也有其他异步模式(例如异步 NSOperation
子类与它们之间的依赖关系,promises/futures,等等)。但是使用异步模式。
我决定采用的方法是编写 getPlaceFromCoordinate 函数来接受可选的闭包,因此调用方法可以控制对查找结果执行的操作。
func getPlaceFromCoordinate(
coordinate: CLLocationCoordinate2D,
placeAction: ((CLPlacemark) -> Void)?
) {
:
// Reverse geocode.
:
// If we get a good placemark:
if (placeAction != nil) {
placeAction!(placemark)
}
}
这对于上下文来说似乎很简单,很灵活并且可以将调用代码放回去 "in the drivers seat"。不确定还有哪些其他优点或缺点。
我正在为这种情况寻找一两个好的成语:
我想通过异步反向地理定位调用将 CLLocationCoordinate2D 转换为 CLPlacemark,作为其他操作序列的一部分。
转换步骤是一个非常重要的 "utility" 步骤,因此在处理程序中放置大量代码来执行 "other operations" 感觉结构很差。
我可以将结果存储在 class 变量中,但是我需要知道异步步骤何时完成,这意味着某种事件触发或主线程排队超时或其他,这也显得别扭。
对此有标准的方法吗?将代码放在处理程序中是否很常见?
谢谢!
这是我的上下文的具体代码,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
闭包中放入了多少代码,以及在 getPlaceFromCoordinate
中放入了多少代码,这完全取决于该代码所包含的内容。但是在 getPlaceFromCoordinate
中重复了很多例行代码(例如记录错误,你有什么),希望闭包将仅限于获取 CLPlacemark
和更新模型对象 and/or UI.
但是,是的,约定是在完成处理程序中放置任何取决于异步方法完成的内容。虽然有一些技术可以使这种异步方法同步运行,但这通常是一个非常糟糕的主意。
如果您发现闭包内的代码变得笨拙,则进行功能分解并将此代码移动到它自己的函数中,让完成处理程序简单地调用它。或者也有其他异步模式(例如异步 NSOperation
子类与它们之间的依赖关系,promises/futures,等等)。但是使用异步模式。
我决定采用的方法是编写 getPlaceFromCoordinate 函数来接受可选的闭包,因此调用方法可以控制对查找结果执行的操作。
func getPlaceFromCoordinate(
coordinate: CLLocationCoordinate2D,
placeAction: ((CLPlacemark) -> Void)?
) {
:
// Reverse geocode.
:
// If we get a good placemark:
if (placeAction != nil) {
placeAction!(placemark)
}
}
这对于上下文来说似乎很简单,很灵活并且可以将调用代码放回去 "in the drivers seat"。不确定还有哪些其他优点或缺点。