Swift地图应用调用locationServicesEnabled()出现UI无响应警告求助
解决CLLocationManager.locationServicesEnabled()的主线程阻塞警告
你遇到的警告根源是CLLocationManager.locationServicesEnabled()在主线程调用时可能导致UI无响应,苹果官方明确建议不要直接在主线程执行这个方法,而是通过locationManagerDidChangeAuthorization回调来处理授权状态检查和后续定位逻辑——你之前把回调内的代码放到DispatchQueue.main.async里没用,因为警告的触发点是if CLLocationManager.locationServicesEnabled()这行本身就在主线程执行。
下面是具体的修改方案和优化后的代码:
修改要点
- 提前设置
CLLocationManager的代理,不要等到判断服务开启后再配置 - 移除
viewDidAppear里的CLLocationManager.locationServicesEnabled()判断,将所有定位相关逻辑移到授权回调方法中 - 不要同时请求
Always和WhenInUse两种授权,根据需求选一种(多数地图场景用WhenInUse即可) - 把地图基础配置(如地图类型、缩放滚动开关)提前到
viewDidLoad,避免重复执行
优化后的代码
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate { let mapView = MKMapView() let manager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() // 地图基础配置只初始化一次 mapView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(mapView) NSLayoutConstraint.activate([ mapView.topAnchor.constraint(equalTo: view.topAnchor), mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor), mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor), mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) mapView.delegate = self mapView.mapType = .standard mapView.isZoomEnabled = true mapView.isScrollEnabled = true mapView.showsUserLocation = false // 提前设置定位管理器代理和精度 manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyBest } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 只请求一种授权,这里选WhenInUse(可根据需求改为Always) manager.requestWhenInUseAuthorization() } // 新增授权状态变化回调,处理定位逻辑 func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { switch manager.authorizationStatus { case .authorizedWhenInUse, .authorizedAlways: // 授权通过后再检查定位服务是否开启 if CLLocationManager.locationServicesEnabled() { manager.startUpdatingLocation() } case .denied, .restricted: // 授权被拒时提示用户(可替换为弹窗引导到设置) print("定位授权被拒绝,请在系统设置中开启") case .notDetermined: // 还未请求授权,已在viewDidAppear中处理,无需额外操作 break @unknown default: break } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // 取最新的位置数据,比直接用manager.location更可靠 guard let myLocation = locations.last else { return } let myCoordinates = myLocation.coordinate let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) let region = MKCoordinateRegion(center: myCoordinates, span: span) mapView.setRegion(region, animated: true) // 避免重复添加标注,先清除旧标注再添加新的 mapView.removeAnnotations(mapView.annotations) let pin = MKPointAnnotation() pin.coordinate = myCoordinates pin.title = "你在这里" mapView.addAnnotation(pin) // 如果不需要实时更新位置,可在这里停止定位 // manager.stopUpdatingLocation() } }
额外说明
- 授权回调
locationManagerDidChangeAuthorization会在授权状态变化时自动触发,包括用户首次授权、后续修改设置等场景 - 使用
locations.last获取最新位置是苹果推荐的做法,比直接访问manager.location更准确 - 如果需要实时跟踪位置,保留
manager.startUpdatingLocation即可;如果只需要一次定位,获取位置后调用manager.stopUpdatingLocation节省资源
内容的提问来源于stack exchange,提问作者user8705895
相关产品推荐
相关产品推荐

