You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift异步逆地理编码获取地址无法返回至saveButton方法问题求助

问题根因

CLGeocoder.reverseGeocodeLocation 是异步方法,不会立刻执行完成,你当前写的同步返回String的getLocation()方法,在逆地理编码的闭包还没返回结果的时候就已经执行结束了,所以永远拿不到地址值。闭包内部的return addr只是结束闭包本身的执行,并不会把值返回到getLocation()的调用方。


解决方案

方案1:闭包回调实现(兼容iOS 11+)

先改造getLocation方法,去掉同步返回,改为通过逃逸闭包回传地址结果:

func getLocation(completion: @escaping (String) -> Void) {
    // 获取坐标
    let result = lm.getLocationCoordinates()
    entryLat = result.0
    entryLong = result.1
    
    let location = CLLocation(latitude: entryLat, longitude: entryLong)
    location.placemark { placemark, error in
        guard let placemark = placemark, let address = placemark.postalAddressFormatted else {
            print("Error:", error ?? "nil")
            completion("Unknown")
            return
        }
        print("formatted address: \(address)")
        completion(address)
    }
}

再改造saveButton方法,将Core Data保存逻辑移到闭包内部,等拿到地址后再执行:

func saveButton() {
    getLocation { [weak self] address in
        guard let self = self else { return }
        self.addr = address
        print("addr = \(address)")
        
        // 保存条目到Core Data
        let newEntry = CurrTrans(context: self.viewContext)
        newEntry.id = UUID()                            
        newEntry.entryDT = self.entryDT
        newEntry.entryDsc = self.entryDsc
        newEntry.moneyD = self.moneyD
        newEntry.entryLat = self.entryLat
        newEntry.entryLong = self.entryLong
        newEntry.address = address
        
        do {
            try self.viewContext.save()
            print("newEntry.address = \(newEntry.address ?? "")")
        } catch {
            print(error.localizedDescription)
        }
    }
}

方案2:async/await实现(iOS 15+ 推荐)

语法更简洁,避免回调嵌套:
首先给CLLocation扩展新增异步方法:

extension CLLocation {
    func getPlacemark() async throws -> CLPlacemark? {
        return try await CLGeocoder().reverseGeocodeLocation(self).first
    }
}

改造saveButton方法,用Task包裹异步逻辑:

func saveButton() {
    // 先获取坐标
    let result = lm.getLocationCoordinates()
    entryLat = result.0
    entryLong = result.1
    let location = CLLocation(latitude: entryLat, longitude: entryLong)
    
    Task {
        do {
            guard let placemark = try await location.getPlacemark(), 
                  let address = placemark.postalAddressFormatted else {
                self.addr = "Unknown"
                return
            }
            self.addr = address
            
            // 保存到Core Data
            let newEntry = CurrTrans(context: self.viewContext)
            newEntry.id = UUID()
            newEntry.entryDT = entryDT
            newEntry.entryDsc = entryDsc
            newEntry.moneyD = moneyD
            newEntry.entryLat = entryLat
            newEntry.entryLong = entryLong
            newEntry.address = address
            
            try viewContext.save()
            print("newEntry.address = \(newEntry.address ?? "")")
        } catch {
            print("逆地理编码错误: \(error.localizedDescription)")
        }
    }
}

注意事项

  • 苹果对逆地理编码接口有调用频率限制,短时间内发起过多请求会返回错误,建议做好防抖或本地缓存逻辑。
  • Core Data的保存操作必须在对应context的队列执行,如果你使用的是主队列context,上述写法无需额外调整。

内容的提问来源于stack exchange,提问作者Galen Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:48:02