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

地理编码报错:kCLErrorDomain错误码1与8排查求助

问题:Firestore地址地理编码时出现kCLErrorDomain错误

从Firestore获取所有用户地址并尝试地理编码为经纬度时,出现以下错误:

2022-07-26 15:40:39.676845-0400 Polygon[96779:3864577] [MKCoreLocationProvider] CLLocationManager(<CLLocationManager: 0x6000004c2c90>) for <MKCoreLocationProvider: 0x6000034f0870> did fail with error: Error Domain=kCLErrorDomain Code=1 "(null)"

以及

Error Error Domain=kCLErrorDomain Code=8 "(null)"

单个地址在其他项目中可正常地理编码,但当前代码运行出错,完整代码如下:

import SwiftUI
import MapKit
import CoreLocationUI
import Firebase

struct Place: Identifiable {
    let id = UUID()
    var name: String
    var coordinate: CLLocationCoordinate2D
}

struct MapView: View {
    
    var empireStateBuilding =
    Place(name: "Empire State Building", coordinate: CLLocationCoordinate2D(latitude: 40.748433, longitude: -73.985656))
    
    @StateObject private var viewModel = ContentViewModel()
    
    @State var address = ""
    @State var addresses:[String] = []
    
    
    
    let geocoder = CLGeocoder()
    @State private var result = "result of lat & long"
    @State private var lat = 0.0
    @State private var long = 0.0
    @State private var country = "country name"
    @State private var state = "state name"
    @State private var zip = "zip code"
    
    var body: some View {
        NavigationView {
            ZStack (alignment: .bottom) {
                Map(coordinateRegion: $viewModel.region, showsUserLocation: true)
                    .ignoresSafeArea()
                    .tint(.pink)
                
                LocationButton(.currentLocation) {
                    viewModel.requestAllowOnceLocationPermission()
                }
                .foregroundColor(.white)
                .cornerRadius(8)
                .labelStyle(.iconOnly)
                .symbolVariant(.fill)
                .tint(.pink)
                .padding(.bottom)
                .padding(.trailing, 300)
                
                Button  {
                    
                    print(address)
                    
                    geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in
                        if((error) != nil){
                            print("Error", error ?? "")
                        }
                        if let placemark = placemarks?.first {
                            if let coordinates:CLLocationCoordinate2D = placemark.location.coordinate {
                                print("Lat: \(coordinates.latitude) -- Long: \(coordinates.longitude)")
                                //added code
                                result = "Lat: \(coordinates.latitude) -- Long: \(coordinates.longitude)"
                                lat = coordinates.latitude
                                long = coordinates.longitude
                            }
                            
                        }
                    })
                    
                    
                    
                } label: {
                    Image(systemName: "arrow.clockwise")
                }
                .padding(.leading, 300)
                .padding(.bottom)
                .cornerRadius(8)
                
                Text("\(result)")
            }
            
            List(0..<addresses.count, id: \.self) {i in Text(addresses[i]) }
            
            
        }
        .onAppear(perform: {
            downloadServerData()
        })
    }
    
    func downloadServerData() {
        let db = Firestore.firestore()
        db.collection("UserInfo").addSnapshotListener {(snap, err) in
            if err != nil{
                print("There is an error")
                return
            }
            for i in snap.documentChanges {
                let documentId = i.document.documentID
                if let address = i.document.get("address") as? String {
                    DispatchQueue.main.async {
                        addresses.append("\(address)")
                        print(address)
                    }
                }
            }
        }
    }
}



struct AnnotatedItem: Identifiable {
    let id = UUID()
    var name: String
    var coordinate: CLLocationCoordinate2D
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

//LocationButton
final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate  {
    @Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 40, longitude: 120), span: MKCoordinateSpan(latitudeDelta: 100, longitudeDelta: 100))
    
    let locationManager = CLLocationManager()
    
    override init() {
        super.init()
        locationManager.delegate = self
    }
    
    func requestAllowOnceLocationPermission() {
        locationManager.requestLocation()
    }
    
    func locationManager( _ _manager:CLLocationManager, didUpdateLocations locations: [CLLocation]){
        guard let latestLocation = locations.first else {
            // show an error
            return
        }
        DispatchQueue.main.async{
            self.region = MKCoordinateRegion(
                center: latestLocation.coordinate,
                span:MKCoordinateSpan(latitudeDelta:0.05, longitudeDelta:0.05))
        }
    }
    
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error.localizedDescription)
    }
}


struct MapView1_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

错误原因及修复建议

1. 位置权限配置缺失

  • Code=1 对应kCLErrorDenied,表示位置权限被拒绝。当前代码直接调用requestLocation(),但未提前请求权限,导致权限被默认拒绝。
    修复:在ContentViewModel的权限请求方法中添加状态检查:
    func requestAllowOnceLocationPermission() {
        switch locationManager.authorizationStatus {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.requestLocation()
        default:
            // 可弹窗提示用户前往设置开启权限
            break
        }
    }
    
    同时必须在Info.plist中添加NSLocationWhenInUseUsageDescription键,填写权限申请说明文本,否则权限请求会直接失败。

2. 地理编码目标地址为空

  • Code=8 对应kCLErrorGeocodeFoundNoResult,当前代码中按钮点击时使用的address变量始终为空字符串(从未被赋值为Firestore获取的地址),导致地理编码请求无结果。
    修复:改为遍历addresses数组批量处理地址:
    Button  {
        for addr in addresses {
            guard !addr.isEmpty else { continue }
            geocoder.geocodeAddressString(addr, completionHandler: {(placemarks, error) -> Void in
                if let error = error {
                    print("地址\(addr)编码失败:", error)
                    return
                }
                if let placemark = placemarks?.first, let coordinates = placemark.location?.coordinate {
                    print("地址\(addr)坐标: Lat: \(coordinates.latitude) -- Long: \(coordinates.longitude)")
                    // 此处可将坐标存入数组或更新UI
                }
            })
        }
    } label: {
        Image(systemName: "arrow.clockwise")
    }
    

3. CLGeocoder实例生命周期不稳定

  • 在MapView结构体中直接声明CLGeocoder,SwiftUI视图会频繁重建,可能导致地理编码请求被中断。
    修复:将geocoder移至ContentViewModel中作为类属性:
    final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate  {
        // ... 其他属性
        let geocoder = CLGeocoder()
        // ... 其他方法
    }
    
    之后在View中通过viewModel.geocoder调用。

4. Firestore快照监听重复添加地址

  • addSnapshotListener会在数据变化时多次触发,当前代码每次触发都会追加所有新文档的地址,导致数组重复。
    修复:只处理新增类型的文档变更:
    for i in snap.documentChanges {
        guard i.type == .added else { continue } // 仅处理新增文档
        if let address = i.document.get("address") as? String {
            DispatchQueue.main.async {
                addresses.append(address)
                print(address)
            }
        }
    }
    

5. CLLocationManagerDelegate方法签名错误

  • locationManager( _ _manager:CLLocationManager, didUpdateLocations locations: [CLLocation])的参数名有多余下划线,导致系统无法正确调用该方法,位置更新失败。
    修复:修正方法签名:
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let latestLocation = locations.first else { return }
        DispatchQueue.main.async{
            self.region = MKCoordinateRegion(
                center: latestLocation.coordinate,
                span:MKCoordinateSpan(latitudeDelta:0.05, longitudeDelta:0.05))
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 03:33:27