Ios GCD信号不等待(Swift)

Ios GCD信号不等待(Swift),ios,swift,grand-central-dispatch,Ios,Swift,Grand Central Dispatch,我对GCD还是个新手。我有这个函数用于前向地理编码,问题是它在完成关闭之前返回。所以每次它都返回零。我发现我可以使用信号量,因此返回将等待完成闭包,但是联机的示例很少,我没有发现任何返回的函数。我试图实现它,但函数仍然返回nil,即使稍后将位置打印到控制台。如果有人能告诉我哪里出了错,我将非常感激 func forwardGeocoding(address: String) -> CLLocation? { var userLocation: CLLocation? var

我对GCD还是个新手。我有这个函数用于前向地理编码,问题是它在完成关闭之前返回。所以每次它都返回零。我发现我可以使用信号量,因此返回将等待完成闭包,但是联机的示例很少,我没有发现任何返回的函数。我试图实现它,但函数仍然返回nil,即使稍后将位置打印到控制台。如果有人能告诉我哪里出了错,我将非常感激

func forwardGeocoding(address: String) -> CLLocation? {
    var userLocation: CLLocation?
    var returnvalue: CLLocation?
    let semaphore = dispatch_semaphore_create(0)

    CLGeocoder().geocodeAddressString(address, completionHandler: { (placemarks, error) in
        if error != nil {
            print("Geocoding error: \(error)")
            return
        }
        if placemarks?.count > 0 {
            let placemark = placemarks?.first
            let location = placemark?.location
            let coordinate = location?.coordinate
            print("Settings location: \(coordinate!.latitude), \(coordinate!.longitude)")
            if let unwrappedCoordinate = coordinate {
                let CLReadyLocation: CLLocation = CLLocation(latitude: unwrappedCoordinate.latitude, longitude: unwrappedCoordinate.longitude)
                userLocation = CLReadyLocation
                dispatch_semaphore_signal(semaphore)
            }
        }
    })

    let wait = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

    if wait != 0 {
        returnvalue = userLocation
    }
    return returnvalue
}

调度信号量等待的结果在成功时为0,在超时时为非零。因此,您应该将代码更改为:
let wait=dispatch\u semaphore\u wait(semaphore,dispatch\u TIME\u ever)

另一点,您必须在块
geocodeAddressString
结束执行之前调用
dispatch\u semaphore\u signal
。否则,您的应用程序将永远等待,以防出现错误

CLGeocoder().geocodeAddressString(address, completionHandler: { (placemarks, error) in
        if error != nil {
            print("Geocoding error: \(error)")
            dispatch_semaphore_signal(semaphore) //add to here
            return
        }
        if placemarks?.count > 0 {
            let placemark = placemarks?.first
            let location = placemark?.location
            let coordinate = location?.coordinate
            print("Settings location: \(coordinate!.latitude), \(coordinate!.longitude)")
            if let unwrappedCoordinate = coordinate {
                let CLReadyLocation: CLLocation = CLLocation(latitude: unwrappedCoordinate.latitude, longitude: unwrappedCoordinate.longitude)
                userLocation = CLReadyLocation
            }
        }
        dispatch_semaphore_signal(semaphore) //and here
    })

最后,当使用永远等待的信号量时,您必须确保信号量内的代码块将结束执行。

正如Paulw11已经提到的,在这种情况下,信号量是非常糟糕的编程习惯。如果您是GCD新手,请学习理解在完成块中返回接收数据的异步模式。Swift比Objective-C更容易处理

这是一个使用完成块的示例:

func forwardGeocoding(address: String, completion: (CLLocation?, NSError?) -> Void) {

  CLGeocoder().geocodeAddressString(address, completionHandler: { (placemarks, error) in
    if error != nil {

      completion(nil, error!)
    } else {
      if let placemarks = placemarks where !placemarks.isEmpty {
        let placemark = placemarks.first!
        if let unwrappedLocation = placemark.location {
          let coordinate = unwrappedLocation.coordinate
          print("Settings location: \(coordinate.latitude), \(coordinate.longitude)")
          let CLReadyLocation = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
          completion(CLReadyLocation, nil)
        }
      }
    }
  })
}
并称之为

forwardGeocoding("foo") { (location, error) in
  if error != nil {
    print("Geocoding error: \(error!)")
  } else {
    // do something with the location
  }
}

你走错了路。您应该将闭包传递给
forwardGeocoding
,并从完成处理程序调用它,而不是试图返回值。您当前的方法很可能会阻塞主队列,特别是在完成处理中,您并不是在所有情况下都像发信号一样发出信号!谢谢你的建议,我肯定需要进一步学习。再次非常感谢。如果您不介意的话,请您向我解释一下“If let placemarks=placemarks where!placemarks.isEmpty”行的具体功能是什么?这让我有点困惑,我很想知道:)没问题,
如果让placemarks=placemarks
打开可选项,如果它不是
nil
,那么
where
子句检查数组是否为空。如果
placemarks
不是
nil
且不是
空的,则
if
条件为真
isEmpty
的同义词。count==0
forwardGeocoding("foo") { (location, error) in
  if error != nil {
    print("Geocoding error: \(error!)")
  } else {
    // do something with the location
  }
}