用户在地图视图中.当在地图上的某个地方长按时,会触发以下函数来设置新的注释,包括正确的标题.
func action(gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.Began {
var newTouch: CGPoint = gestureRecognizer.locationInView(self.mapView)
var newCoordinate: CLLocationCoordinate2D = mapView.convertPoint(newTouch, toCoordinateFromView: self.mapView)
var newLocation = CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude)
var newAnnotation = MKPointAnnotation()
newAnnotation.coordinate = newCoordinate
CLGeocoder().reverseGeocodeLocation(newLocation, completionHandler: {(placemarks, error) in
if error != nil { println(error) }
let p: CLPlacemark = placemarks[0] as CLPlacemark
var thoroughfare: String? = p.thoroughfare
var subThoroughfare: String? = p.subThoroughfare
if p.thoroughfare == nil || p.subThoroughfare == nil {
var date = NSDate()
newAnnotation.title = "Added \(date)"
} else {
newAnnotation.title = thoroughfare! + " " + subThoroughfare!
}
})
self.mapView.addAnnotation(newAnnotation)
self.mapView.selectAnnotation(newAnnotation, animated: true)
places.append(["name":"\(newAnnotation.title)", "lat":"\(newCoordinate.latitude)", "lon":"\(newCoordinate.longitude)"])
}
}
Run Code Online (Sandbox Code Playgroud)
我知道在CLGeocoder块中保留最后三行代码(闭包?)时工作正常.但是,如果我将它们分开并将它们列在})(或将一些代码放到另一个线程之后)我面临的问题是它运行异步(因为我不明白如何控制异步vs同步)并且当时注释将添加到地图并保存到CLGeocoder尚未设置其标题的位置.编程的初学者问:实现什么是必要的(disptach_sync ...-某事)所以最后一行代码等待CLGeocoder块完成?我还没有设法以正确的方式实现这个命令......
您正确地指出,当您将这三行放入地理编码器的闭包中时,它会起作用.因此,您应该这样做:利用这种异步模式,并将所有依赖于地理编码过程的内容放在闭包中.
回答你的问题,是的,有些模式可以使异步任务以同步方式运行.例如,您可以使用调度组或调度信号量.但是你从一个IBAction运行在主线程上的这个调用它.你永远不想阻止主线程.因此,任何使这个地理编码请求从主线程同步运行的尝试都是不明智的.
此外,上面的过程因以下问题而变得复杂reverseGeocodeLocation:具体来说,闭包本身在主线程上运行,因此如果你阻塞主线程等待闭包完成,应用程序将会死锁.所以上面的模式甚至不能使用reverseGeocodeLocation(如果从主线程完成).
最重要的是,您应该接受异步模式,将依赖代码保留在闭包内.
顺便说一句,你的例子很简单,你只需要在地理编码器的闭包中输入你想要执行的代码.但是,如果您想要两个单独的函数,例如,一个用于返回注释的地理编码,另一个函数用于将注释添加到地图,该怎么办?也许你期待的是:
func handleLongPress(gesture: UILongPressGestureRecognizer) {
if gesture.state == .Began {
let location = gesture.locationInView(self.mapView)
let annotation = geocodeLocationInMapView(self.mapView, location: location)
addAnnotationToMapView(self.mapView, annotation: annotation)
}
}
Run Code Online (Sandbox Code Playgroud)
然后问题是你将如何获得第二个功能addAnnotationToMapView,等待第一个功能geocodeLocationInMapView完成.同样,答案是"你没有." 相反,就像Apple使用异步方法一样,您将使用完成块模式:
func handleLongPress(gesture: UILongPressGestureRecognizer) {
if gesture.state == .Began {
let location = gesture.locationInView(self.mapView)
geocodeLocationInMapView(self.mapView, location: location) { annotation, error in
guard annotation != nil && error == nil else {
print("error = \(error)")
return
}
self.addAnnotationToMapview(self.mapView, annotation: annotation!)
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,geocodeLocationInMapView可能看起来像:
func geocodeLocationInMapView(mapView: MKMapView, location: CGPoint, completion: (MKAnnotation?, NSError?) -> ()) {
let coordinate = mapView.convertPoint(location, toCoordinateFromView: mapView)
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
guard placemarks != nil && error == nil else {
completion(nil, error)
return
}
if let placemark = placemarks!.first {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
let thoroughfare = placemark.thoroughfare
let subThoroughfare = placemark.subThoroughfare
switch (thoroughfare, subThoroughfare) {
case (nil, nil):
annotation.title = "Added \(NSDate())"
case (_, nil):
annotation.title = thoroughfare
default:
annotation.title = thoroughfare! + " " + subThoroughfare!
}
completion(annotation, nil)
}
}
}
Run Code Online (Sandbox Code Playgroud)
而addAnnotationToMapview可能是这样的:
func addAnnotationToMapview(mapView: MKMapView, annotation: MKAnnotation) {
mapView.addAnnotation(annotation)
mapView.selectAnnotation(annotation, animated: true)
places.append(["name":"\(annotation.title)", "lat":"\(annotation.coordinate.latitude)", "lon":"\(annotation.coordinate.longitude)"])
}
Run Code Online (Sandbox Code Playgroud)
诚然,这是一个人为的例子,我建议你按照IBAction我在这个答案开头所描述的那样处理你的问题.但是在回答更广泛的问题"我如何使函数A等到函数B完成"之后,您可以使用此处概述的完成块模式.
| 归档时间: |
|
| 查看次数: |
3548 次 |
| 最近记录: |