Swift开发中如何等待CLGeocoder逆地理编码执行完成?
解决方案
核心原因
CLGeocoder的reverseGeocodeLocation本身是异步API,内部会在系统队列执行网络/本地查询逻辑,直接把函数调用放到同步队列也不会等待回调执行,所以之前的方案不生效。
方案1:闭包回调(全系统版本兼容,最常用)
把原函数改造为带完成回调的形式,后续逻辑直接放到回调内部执行即可,同时修复原代码强制解包可能导致的崩溃问题:
private func getAddressFromLocation(forLocation: CLLocationCoordinate2D, completion: @escaping (String?) -> Void) { let geoCoder = CLGeocoder() geoCoder.reverseGeocodeLocation(CLLocation(latitude: forLocation.latitude, longitude: forLocation.longitude), completionHandler: {(places, error) in guard error == nil, let place = places?.first else { completion(nil) return } var address: [String] = [] if let country = place.country { address.append(country) } if let postalCode = place.postalCode { address.append(postalCode) } if let locality = place.locality { address.append(locality) } if let thoroughfare = place.thoroughfare { address.append(thoroughfare) } let fullAddress = address.joined(separator: ",") self.fullAddress = fullAddress completion(fullAddress) }) }
调用示例:
// 调用位置 getAddressFromLocation(forLocation: 需要解析的坐标) { [weak self] address in guard let self = self, let address = address else { // 处理解析失败的逻辑 return } // 地址赋值完成,后续逻辑写在这里 print("已获取地址: \(address)") }
方案2:Async/Await(iOS 15+ 推荐)
如果你的App最低支持iOS 15,用Swift原生的异步写法逻辑更清晰,避免回调嵌套:
改造后的函数:
@available(iOS 15.0, *) private func getAddressFromLocation(forLocation: CLLocationCoordinate2D) async throws -> String { let geoCoder = CLGeocoder() let places = try await geoCoder.reverseGeocodeLocation(CLLocation(latitude: forLocation.latitude, longitude: forLocation.longitude)) guard let place = places.first else { throw NSError(domain: "GeocodeError", code: -1, userInfo: [NSLocalizedDescriptionKey: "未匹配到地址信息"]) } var address: [String] = [] if let country = place.country { address.append(country) } if let postalCode = place.postalCode { address.append(postalCode) } if let locality = place.locality { address.append(locality) } if let thoroughfare = place.thoroughfare { address.append(thoroughfare) } let fullAddress = address.joined(separator: ",") self.fullAddress = fullAddress return fullAddress }
调用示例:
Task { do { let address = try await getAddressFromLocation(forLocation: 需要解析的坐标) // 地址赋值完成,后续逻辑写在这里 print("已获取地址: \(address)") } catch { // 处理解析失败逻辑 print("地址解析失败: \(error.localizedDescription)") } }
不推荐方案:DispatchSemaphore 同步阻塞
如果一定要实现同步等待的效果,可以用信号量实现,但绝对不要在主线程调用,否则会阻塞主线程事件循环导致APP无响应:
// 仅可在后台线程调用,主线程调用会卡死 private func getAddressSync(forLocation: CLLocationCoordinate2D) -> String? { let semaphore = DispatchSemaphore(value: 0) var result: String? let geoCoder = CLGeocoder() geoCoder.reverseGeocodeLocation(CLLocation(latitude: forLocation.latitude, longitude: forLocation.longitude)) { places, error in defer { semaphore.signal() } guard error == nil, let place = places?.first else { result = nil return } var address: [String] = [] if let country = place.country { address.append(country) } if let postalCode = place.postalCode { address.append(postalCode) } if let locality = place.locality { address.append(locality) } if let thoroughfare = place.thoroughfare { address.append(thoroughfare) } result = address.joined(separator: ",") self.fullAddress = result } semaphore.wait() return result }
内容的提问来源于stack exchange,提问作者Dawy
相关产品推荐
相关产品推荐

