Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function 如何让函数A等待进行,直到被调用的函数B完成_Function_Swift - Fatal编程技术网

Function 如何让函数A等待进行,直到被调用的函数B完成

Function 如何让函数A等待进行,直到被调用的函数B完成,function,swift,Function,Swift,用户位于地图视图上。当在地图上的某个地方长按时,将触发以下函数以设置新注释(包括适当的标题) func action(gestureRecognizer: UIGestureRecognizer) { if gestureRecognizer.state == UIGestureRecognizerState.Began { var newTouch: CGPoint = gestureRecognizer.locationInView(self.mapView)

用户位于地图视图上。当在地图上的某个地方长按时,将触发以下函数以设置新注释(包括适当的标题)

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)"])

    }

}
我知道,将最后三行代码保留在CLGeocoder块内(闭包?)效果良好。但是如果我将它们分开,并在
}
之后列出它们(或者将一些代码放到另一个线程中),我将面临一个问题,即它是异步运行的(因为我不知道如何控制async vs sync),并且在将注释添加到地图并保存到其他位置时,CLGeocoder尚未设置其标题。
编程初学者会问:需要实现什么(disptach\u sync…-什么东西),所以最后一行代码等待CLGeocoder块完成?我还没有以正确的方式实现这个命令…

您正确地指出,当您将这三行放在地理编码器的闭包中时,它是有效的。因此,您应该准确地做到这一点:利用这个异步模式,将所有依赖于地理代码流程的内容都放在闭包中

回答您的问题,是的,有一些模式可以使异步任务以同步方式运行。例如,您可以使用调度组或调度信号量。但是您是从运行在主线程上的
iAction
调用它的。你永远不想阻塞主线程。因此,任何试图使此地理代码请求从主线程同步运行的尝试都是不明智的

此外,上面的过程由于
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)
    }
}
然后问题是如何让第二个函数,
addAnnotationToMapView
,等待第一个函数,
geocodelocationinmpview
完成。同样,答案是“你没有”。相反,就像苹果使用异步方法一样,你会采用一种完成块模式:

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!)
        }
    }
}
在这种情况下,
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)
        }
    }
}
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)"])
}
将注释添加到pview
可能如下所示:

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)
        }
    }
}
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)"])
}

诚然,这是一个做作的例子,我建议您按照我在回答开头所描述的那样处理
iAction
。但在回答更广泛的问题“如何让函数A等待函数B完成”时,您可以使用此处概述的完成块模式。

您正确地指出,当您将这三行放在地理编码器的闭包中时,它是有效的。因此,您应该准确地做到这一点:利用这个异步模式,将所有依赖于地理代码流程的内容都放在闭包中

回答您的问题,是的,有一些模式可以使异步任务以同步方式运行。例如,您可以使用调度组或调度信号量。但是您是从运行在主线程上的
iAction
调用它的。你永远不想阻塞主线程。因此,任何试图使此地理代码请求从主线程同步运行的尝试都是不明智的

此外,上面的过程由于
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)
    }
}
然后问题是如何让第二个函数,
addAnnotationToMapView
,等待第一个函数,
geocodelocationinmpview
完成。同样,答案是“你没有”。相反,就像苹果使用异步方法一样,你会采用一种完成块模式:

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!)
        }
    }
}
在这种情况下,
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)
        }
    }
}
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)"])
}
将注释添加到pview
可能如下所示:

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)
        }
    }
}
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)"])
}

诚然,这是一个做作的例子,我建议您按照我在回答开头所描述的那样处理
iAction
。但在回答“如何让函数A等待函数B完成”这一更广泛的问题时,您可以使用此处概述的完成块模式。

查找调度组。此处信息不足。假设
namingAnnotation
是同步的,则无需采取进一步行动。我编辑了问题以指出我的实际问题。我知道这是一个广泛使用的(也是众所周知的)主题,但由于我是编程新手,有时我还没有正确理解我一直在阅读的指南。@Abizern您可以使用调度组(或信号量)使异步函数的行为类似于同步o