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

Xcode15.3+Swift5.10下UIKit无法显示用户当前位置求助

问题描述

使用Xcode15.3、Swift5.10开发地图功能,需求是用户授权后显示当前位置并添加大头针。已配置Info.plist、相关函数及IBOutlet,但运行时出现以下问题:

  • 控制台警告:This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the -locationManagerDidChangeAuthorization:callback and checkingauthorizationStatus first
  • 控制台报错:Error Domain=kCLErrorDomain Code=1 "(null)"
  • 地图仅显示英国区域,未加载用户当前位置及大头针

原代码如下:

import UIKit
import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {

    @IBOutlet weak var myMap: MKMapView!
    
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        
        if (CLLocationManager.locationServicesEnabled()) {
            
            locationManager.requestLocation()
            locationManager.startUpdatingLocation()
       }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        if let userLocation = locations.first {
            manager.stopUpdatingLocation()
            
        let coordinate = CLLocationCoordinate2D(latitude: locationManager.location?.coordinate.latitude ?? 0.0, longitude: locationManager.location?.coordinate.longitude ?? 0.0)
            
        let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        myMap.setRegion(region, animated: true)
        let myPin = MKPointAnnotation()
        myPin.coordinate = coordinate
        myPin.title = "Hey There"
        myPin.subtitle = "I am here"
        myMap.addAnnotation(myPin)
            
        }
    }
  
   
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        
        switch manager.authorizationStatus {
        case .authorizedAlways:
            return
        case .authorizedWhenInUse:
            return
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted:
            locationManager.requestWhenInUseAuthorization()
        case .denied:
            return
        @unknown default:
            locationManager.requestWhenInUseAuthorization()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) {
        print(error)
    }
}
问题原因分析
  1. 授权时机错误:viewDidLoad中直接调用位置更新方法,此时可能未获取用户授权,触发权限不足错误(kCLErrorDomain Code=1)。
  2. 授权回调逻辑缺失:locationManagerDidChangeAuthorization中,授权成功后未启动位置更新,导致授权完成后无后续位置获取动作。
  3. 位置获取逻辑冗余:同时调用requestLocation和startUpdatingLocation,前者是单次获取,后者是持续更新,二者重复调用无意义。
  4. 坐标获取方式不当:已通过didUpdateLocations拿到最新位置,却又使用locationManager.location,可能导致空值或旧坐标。
修复后的代码
import UIKit
import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {

    @IBOutlet weak var myMap: MKMapView!
    
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        
        // 主动检查授权状态,触发回调逻辑
        locationManagerDidChangeAuthorization(locationManager)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let userLocation = locations.first else { return }
        
        manager.stopUpdatingLocation()
        
        // 使用回调中的最新位置坐标
        let coordinate = userLocation.coordinate
        let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        
        // 确保UI操作在主线程执行
        DispatchQueue.main.async {
            self.myMap.setRegion(region, animated: true)
            
            let myPin = MKPointAnnotation()
            myPin.coordinate = coordinate
            myPin.title = "Hey There"
            myPin.subtitle = "I am here"
            self.myMap.addAnnotation(myPin)
        }
    }
  
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        switch manager.authorizationStatus {
        case .authorizedAlways, .authorizedWhenInUse:
            // 授权成功后启动位置更新
            manager.startUpdatingLocation()
        case .notDetermined:
            manager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            // 权限不足时提示用户去设置开启
            let alert = UIAlertController(title: "位置权限不足", message: "请在设置中开启位置权限以获取当前位置", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in
                guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
                UIApplication.shared.open(settingsURL)
            })
            present(alert, animated: true)
        @unknown default:
            manager.requestWhenInUseAuthorization()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) {
        print("位置获取失败:\(error.localizedDescription)")
    }
}
关键修复点说明
  • 调整授权触发逻辑:viewDidLoad中主动调用授权检查方法,避免未授权时启动位置更新。
  • 完善授权成功处理:授权通过后立即启动位置更新,确保授权后才开始获取位置。
  • 优化坐标使用:直接使用回调中的最新位置,避免依赖locationManager.location的潜在问题。
  • 主线程保障UI操作:将地图区域设置和大头针添加放在主线程执行,避免UI卡顿。
  • 权限不足提示:针对受限/拒绝状态添加弹窗引导,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:10:35