Swift中CLGeocoder异步回调类型不匹配报错求助
问题原因与解决方案
错误根源
两个错误的核心原因是:你在CLGeocoder.geocodeAddressString(_:completionHandler:)的回调闭包里使用了try await,导致闭包变成**async throws类型**,但该方法要求的是同步、非抛出的闭包类型,类型不匹配所以报错。
修复步骤
- 改用CLGeocoder的Async/Await版本API(iOS 15+支持),替代传统的回调闭包,避免闭包内的异步冲突。
- 将异步逻辑包裹在Task中(如果在同步上下文执行,比如
viewDidLoad)。 - 处理所有可选值和错误,替换占位符
<#default value#>为实际默认值,避免编译错误。 - 完善图片保存的容错处理,防止
pngData()为nil导致的崩溃。
修复后的完整代码
import CoreLocation import MapKit import UIKit import CSV // 假设你用的是CSV库处理文件 let columnTypes: [String: CSVType] = ["LABE": .string, "HAUS": .string, "Gemeindename": .string] enum LookaroundError: Error { case unableToCreateScene case invalidAddress case failedToGetImageData } func snapshotImage(for coordinate: CLLocationCoordinate2D) async throws -> UIImage { guard let scene = try await MKLookAroundSceneRequest(coordinate: coordinate).scene else { throw LookaroundError.unableToCreateScene } let options = MKLookAroundSnapshotter.Options() options.size = CGSize(width: 1000, height: 500) return try await MKLookAroundSnapshotter(scene: scene, options: options).snapshot.image } // 把核心逻辑放到异步函数中 func processAddresses() async { guard let path = Bundle.main.url(forResource: "Adresse", withExtension: "csv") else { print("找不到CSV文件") return } let options = CSVReadingOptions( hasHeaderRow: true, ignoresEmptyLines: true, delimiter: ";" ) do { let result = try DataFrame(contentsOfCSVFile: path, rows: 0..<50, types: columnTypes, options: options) let geocoder = CLGeocoder() for row in result.rows { // 替换占位符为实际默认值(比如空字符串) let label = row["LABE"] ?? "" let haus = row["HAUS"] ?? "" let gemeinde = row["Gemeindename"] ?? "" let address = haus.isEmpty ? "\(label) \(gemeinde)" : "\(label) \(haus) \(gemeinde)" print("处理地址:\(address)") // 使用Async/Await版本的地理编码API let placemarks = try await geocoder.geocodeAddressString(address) guard let coordinate = placemarks.first?.location?.coordinate else { throw LookaroundError.invalidAddress } // 获取快照图片 let image = try await snapshotImage(for: coordinate) // 准备保存路径,替换地址中的非法文件名字符 let safeAddressName = address.replacingOccurrences(of: "/", with: "-") let saveURL = try FileManager.default .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) .appending(component: "\(safeAddressName).png") // 处理pngData可能为nil的情况 guard let imageData = image.pngData() else { throw LookaroundError.failedToGetImageData } try imageData.write(to: saveURL) print("图片已保存到:\(saveURL)") } } catch { print("处理出错:\(error.localizedDescription)") } } // 在合适的地方调用(比如viewDidLoad中) // Task { // await processAddresses() // }
关键修改点说明
- 替换地理编码API:用
geocodeAddressString(_:) async throws -> [CLPlacemark]替代回调版本,直接用await获取结果,避免闭包类型不匹配。 - 封装异步逻辑:把整个处理流程放到
processAddresses()异步函数中,确保可以使用await。 - 可选值处理:替换
<#default value#>为空字符串,用isEmpty判断HAUS字段是否存在,简化地址拼接逻辑。 - 文件名容错:地址中可能包含
/等非法文件名字符,用replacingOccurrences(of:with:)替换,避免保存失败。 - 错误处理:新增自定义错误类型,用
do-catch包裹所有可能抛出错误的操作,确保程序稳定性。
内容的提问来源于stack exchange,提问作者Pooriya Rezaei
相关产品推荐
相关产品推荐

