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

iOS定位问题:didUpdateLocations与授权回调未触发

定位回调未触发问题的解决方案

问题说明

尝试获取设备定位时,locationManager(_:didChangeAuthorization:) 和 locationManager(_:didUpdateLocations:) 两个回调始终无法触发。系统会正常请求定位权限,且已完成授权,但第二次调用startLocation方法时,仅能看到权限授予的打印日志,回调仍无响应。

调用代码如下:

DispatchQueue.global(qos: .background).async {
    let gpsController = GPSController()
    gpsController.startLocation()
    
    sleep(10)
        DispatchQueue.main.async {
            gpsController.startLocation()
        }
}

我的GPSController实现代码:

import Foundation
import CoreLocation

class GPSController : NSObject, CLLocationManagerDelegate{

let locationManager: CLLocationManager = CLLocationManager()
static var lastLocation : CLLocation? = nil


func startLocation(){
    locationManager.delegate = self
    
    // 检查定位服务状态
    if CLLocationManager.locationServicesEnabled() {
        switch locationManager.authorizationStatus {
        case .notDetermined:
            print("notDetermined")
            locationManager.requestWhenInUseAuthorization()
            break
        case .restricted, .denied:
            print("Denied")
            break
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
            print("authorizedWhenInUse")
        case .authorized:
            print("authorized")
            break
        @unknown default:
            print("@unknown")
            break
        }
    } else {
        print("turn off")
    }
    
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    print("didChangeAuthorization")
    if manager.authorizationStatus == .authorizedWhenInUse {
        locationManager.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("didChangeAuthorization") // 此处打印内容错误,应为didUpdateLocations
    for currentLocation in locations{
        Loge("Location : \(currentLocation)")
        GPSController.lastLocation = currentLocation
    }
}


func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("error")
}    

解决方案

1. 核心问题:GPSController实例被提前回收

在后台队列闭包中创建的gpsController是局部变量,当闭包执行周期结束后,该实例会被ARC自动回收,导致CLLocationManager的代理失效,无法触发回调。

修复方式:

  • 方式一:通过全局变量或类属性持有实例,保证其生命周期
// 在闭包外部声明持有变量
var gpsController: GPSController?

DispatchQueue.global(qos: .background).async {
    gpsController = GPSController()
    gpsController?.startLocation()
    
    sleep(10)
        DispatchQueue.main.async {
            gpsController?.startLocation()
        }
}
  • 方式二:将GPSController设计为单例,确保全局唯一且不会被回收
class GPSController : NSObject, CLLocationManagerDelegate{
    static let shared = GPSController() // 单例实例
    let locationManager: CLLocationManager = CLLocationManager()
    static var lastLocation : CLLocation? = nil

    private override init() { // 私有化构造方法,避免创建多个实例
        super.init()
        locationManager.delegate = self // 初始化时统一设置代理,无需重复调用
    }

    // 剩余方法保持不变
}

// 调用方式
DispatchQueue.global(qos: .background).async {
    GPSController.shared.startLocation()
    
    sleep(10)
        DispatchQueue.main.async {
            GPSController.shared.startLocation()
        }
}

2. 次要问题修正

  • 修正didUpdateLocations中的打印错误,将print("didChangeAuthorization")改为print("didUpdateLocations"),便于确认回调是否触发。
  • 确保Info.plist中添加了对应权限描述:
    • 使用requestWhenInUseAuthorization时,需添加NSLocationWhenInUseUsageDescription键并补充描述文本;
    • 使用requestAlwaysAuthorization时(iOS 11+),需添加NSLocationAlwaysAndWhenInUseUsageDescription键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:42:53