当前位置: 首页 > news >正文

This method can cause UI unresponsiveness if invoked on the main thread.

Xcode编译运行报错:This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the `-locationManagerDidChangeAuthorization:` callback and checking `authorizationStatus` first.

问题根源

这个警告的核心意思是:你正在主线程(UI线程)上同步地检查定位权限授权状态(authorizationStatus),而这个操作可能会因为需要与底层硬件或系统进程通信而产生延迟,从而阻塞主线程,导致界面卡顿、无响应

在 iOS 中,所有UI的绘制和交互都发生在主线程。如果主线程被长时间阻塞,用户就会感觉到应用“卡住了”。

解决方案

正确的做法是采用异步的方式来获取和响应授权状态的变化。主要有以下两种方法:

方法一:使用 locationManagerDidChangeAuthorization: 委托回调(推荐,iOS 14+)

这是 Apple 在现代 iOS 版本中推荐的方式。你需要实现 CLLocationManagerDelegate 中的这个新方法,它会在应用的定位权限发生任何变化时被调用(例如用户首次选择、在系统设置中更改等)。

步骤如下:

  1. 设置委托(Delegate):确保你的 CLLocationManager 实例设置了 delegate

  2. 实现回调方法:在委托对象中实现 locationManagerDidChangeAuthorization: 方法。

  3. 在回调中处理逻辑:在这个方法内部,根据当前的授权状态来执行你的后续操作(如开始更新位置、显示地图等)。

代码示例:

#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#import "HDLocatoinViewController.h"@interface HDLocatoinViewController ()<CLLocationManagerDelegate>@property (strong, nonatomic) CLLocationManager *locationManager;@end@implementation HDLocatoinViewController- (void)viewDidLoad {[super viewDidLoad];// 初始化位置管理器并设置代理self.locationManager = [[CLLocationManager alloc] init];self.locationManager.delegate = self;// 不要在这里直接检查 authorizationStatus// 可以在这里请求授权(如果需要),但要先检查locationServiceEnable,也就是定位服务总开关有没有打开// [self locationAuthorization];
}- (void)locationAuthorization{// 在主线程上异步检查定位服务dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{BOOL locationServicesEnabled = [CLLocationManager locationServicesEnabled];dispatch_async(dispatch_get_main_queue(), ^{if (locationServicesEnabled == NO) {[self showLocationServicesDisabledAlert];} else {[self.locationManager requestWhenInUseAuthorization];}});});
}#pragma mark - CLLocationManagerDelegate- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {// 在授权状态变化时安全地检查if (@available(iOS 14.0, *)) {[self handleLocationAuthorization:manager.authorizationStatus];}
}// 为了兼容 iOS 13 及以下版本,也可以实现旧版代理方法
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {if (@available(iOS 14.0, *)) {// 在 iOS 14+ 上,使用新的 locationManagerDidChangeAuthorization: 方法return;}[self handleLocationAuthorization:status];
}- (void)handleLocationAuthorization:(CLAuthorizationStatus)status {switch (status) {case kCLAuthorizationStatusAuthorizedAlways:case kCLAuthorizationStatusAuthorizedWhenInUse:// 权限已授予,开始定位NSLog(@"定位权限已授予,开始更新位置...");[self.locationManager startUpdatingLocation];break;case kCLAuthorizationStatusDenied:case kCLAuthorizationStatusRestricted:// 权限被拒绝或受限NSLog(@"定位权限被拒绝");[self showPermissionAlert];break;case kCLAuthorizationStatusNotDetermined:// 尚未决定,通常不会在这里触发NSLog(@"尚未请求权限");break;default:break;}
}- (void)showLocationServicesDisabledAlert {UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"定位服务已关闭"message:@"请前往「设置」→「隐私与安全性」→「定位服务」中开启定位功能,以便使用此应用的位置服务"preferredStyle:UIAlertControllerStyleAlert];// 取消按钮UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancelhandler:nil];// 前往设置按钮UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:@"前往设置"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {// 跳转到系统的定位服务设置页面NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];if (@available(iOS 10.0, *)) {[[UIApplication sharedApplication] openURL:settingsURL options:@{} completionHandler:nil];} else {// 兼容 iOS 10 以下版本[[UIApplication sharedApplication] openURL:settingsURL];}}];[alert addAction:cancelAction];[alert addAction:settingsAction];[self presentViewController:alert animated:YES completion:nil];
}- (void)showPermissionAlert {// 提示用户去设置中开启权限UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"需要定位权限"message:@"请前往「设置」->「隐私与安全性」->「定位服务」中允许本应用使用定位"preferredStyle:UIAlertControllerStyleAlert];UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];if ([[UIApplication sharedApplication] canOpenURL:settingsURL]) {[[UIApplication sharedApplication] openURL:settingsURL options:@{} completionHandler:nil];}}];[alert addAction:cancelAction];[alert addAction:settingsAction];[self presentViewController:alert animated:YES completion:nil];
}#pragma mark - 用户操作触发请求授权- (IBAction)requestLocationPermissionButtonTapped:(id)sender {// 当用户执行需要定位功能的操作时请求授权[self locationAuthorization];
}@end
方法二:在适当的时机请求授权,而非直接检查状态

很多时候,你并不需要主动去“检查”状态,而是应该在用户执行某个需要定位功能的操作时,去“请求”授权。

  • 场景:用户点击了一个“获取当前位置”的按钮。

  • 做法:直接在按钮的 @IBAction 方法中调用 requestWhenInUseAuthorization()。如果权限已经是 .authorized,这个请求会被系统忽略;如果还没决定,系统会弹出提示框;如果已被拒绝,你可以在 locationManagerDidChangeAuthorization: 中处理(如方法一所示)。

总结与最佳实践

  1. 避免同步检查:永远不要在 viewDidLoad 或其他主线程方法中直接使用 CLLocationManager.authorizationStatus() 来决定UI流程。

  2. 拥抱异步回调:依赖 locationManagerDidChangeAuthorization: 这个委托方法来响应权限状态的变化。这是最安全、最现代的方式。

  3. 按需请求:在用户意图明确(如点击相关按钮)时再请求定位权限,这样系统提示框的出现对用户来说更合情合理,通过率也更高。

  4. 处理所有状态:在你的代码中妥善处理 .notDetermined(未决定)、.authorized(已授权)、.denied(已拒绝)等所有可能的授权状态,提供良好的用户引导。

好的,解决方案知道了,现在问题是这个报报错到底是哪行代码产生的,因为一个项目中可能有很多模块都有定位功能权限的调用,所以我们现在要查找问题代码产生行

步骤如下:

第一步:点击Xcode左侧工具栏上的警告图标,如下图

第二步:点击左下角的过滤图标,并选择“ISSUE KIND Build”,如下图

第三步:点击Build在弹出的列表中选择Run,并将右下角的蓝色小圆叉点击一下,置灰,如下图

第四步:第三步结束后就能看到过滤内容区显示了警告的具体原因,可以点击小三角展开查看具体代码行,如下图

奇迹出现了,报错代码行产生了,如下图

这里明显能看出是极光推送模块中JCommonCollectLocationManager这个类里面调用了定位权限代码导致的警告,升级极光推送SDK,解决问题!

http://www.dtcms.com/a/353435.html

相关文章:

  • week5-[字符数组]数和
  • 【技巧】PostgreSQL自动转换类型 int转bool 转int
  • 苍穹外卖项目实战(日记十一)-记录实战教程及问题的解决方法-(day3-3)完善菜品分页查询功能
  • 怎么理解API?
  • 用户体验设计 | 什么是 AX?从 UX 到 AX 的演进
  • 数据结构——算法效率的度量(时间复杂度与空间复杂度)
  • Elasticsearch 启动反复重启排查实录:从“内存不足”到“vm.max\_map\_count 过小”
  • 图表可视化地理趋势-Telerik WPF Chart
  • 智能汽车制造:海康NVR管理平台/工具EasyNVR多品牌NVR管理工具/设备实现无插件视频监控直播方案
  • R语言贝叶斯方法在生态环境领域中的技术应用
  • 攻克 Java 分布式难题:并发模型优化与分布式事务处理实战指南
  • APP与WEB测试的区别?
  • 人工智能在医疗领域中辅助外科手术的应用综述
  • 【VSCode】使用VSCode创建Java C/S架构项目
  • 如何用Renix实现网络测试自动化: 从配置分离到多厂商设备支持
  • 【网络编程】NtyCo协程服务器的框架(轻量级的协程方案,人称 “小线程”)
  • 从浏览器无法访问到Docker容器的 FastAPI 服务地址【宿主机浏览器和容器不在同一个网络层面:端口映射】
  • 前端AI应用实践指南:从基础概念到高级实现
  • 云手机的未来发展怎么样?
  • 数据结构(C语言篇):(二)顺序表
  • 状态设计模式
  • 手机冻结技术发展时间轴
  • Flutter项目详解
  • 深度学习实战117-各种大模型(Qwen,MathGPT,Deepseek等)解高考数学题的应用,介绍架构原理
  • C++工程实战入门笔记6-函数(三)关于base16编码的原理和函数模块化实战
  • LINUX --- 网络编程(二)
  • OpenAi在中国拿下“GPT”商标初审!
  • October 2019 Twice SQL Injection
  • Qt图片上传系统的设计与实现:从客户端到服务器的完整方案
  • 对比视频处理单元(VPU)、图形处理器(GPU)与中央处理器(CPU)