我对GCD很陌生。我有这个函数用于前向地理编码,问题是它在完成闭包完成之前返回。所以每次它只返回 nil 。我发现我可以使用信号量,所以返回等待完成闭包完成,但是在网上有很少的例子,我发现没有返回的函数。我尝试实现它,但函数仍然返回 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 :(得分:1)
正如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
}
}
答案 1 :(得分:0)
dispatch_semaphore_wait的结果在成功时为0,在超时时为非零。因此,您应该将代码更改为:
let wait = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
if wait == 0 { //your work is done, without time out.
returnvalue = userLocation //update location
}
return returnvalue //otherwise return nil according to your code above. this code will never execute. In this case, there is no time out cause it wait forever.
另一点,您必须在阻止dispatch_semaphore_signal
结束执行之前调用geocodeAddressString
。否则,如果出现错误,您的应用程序将永远等待。
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
})
最后,当使用永远等待的信号量时,你必须确保信号量内的代码块将结束执行。