iOS14中Objective-C二维码扫描弹出UIAlertController崩溃问题求助
iOS 14 扫码弹窗崩溃问题定位与修复
崩溃根因
AVCaptureSession 的元数据识别回调本身运行在系统分配的后台队列,并非主线程。
- iOS 12、iOS 13 版本未对 AutoLayout 引擎做严格的线程强校验,后台线程创建
UIAlertController触发的布局初始化操作不会立刻触发崩溃 - 从 iOS 14 开始,系统强化了 AutoLayout 的线程安全规则:只要引擎之前被主线程访问过,后续所有布局相关的初始化、修改操作,强制要求在主线程执行,一旦检测到后台线程操作,直接抛出
NSInternalInconsistencyException终止进程
你现有代码仅将stopReading方法调度到主线程执行,后续创建弹窗、添加事件、控制器跳转的全量UI逻辑,仍然留在扫码回调的后台线程中,直接触发了iOS14的新增校验规则。该问题本质是违反了UIKit操作必须在主线程执行的开发规范,旧系统只是没有做硬拦截,并非代码逻辑完全合法。
修复方案
将扫码后所有涉及UI渲染、控制器交互的逻辑,统一收敛到主线程队列执行即可解决问题:
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0]; if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) { // 在后台回调中完成纯数据提取,避免切换线程时丢失识别结果 NSString *codeString = [metadataObj stringValue]; // 所有UI操作整体切回主线程执行 dispatch_async(dispatch_get_main_queue(), ^{ [self stopReading]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"QRCode is Scanned" message:@"" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { NSLog(@"The Scanned QRCode as %@", codeString); [self.delegate addItemViewController:self didFinishEnteringItem:codeString]; [self.navigationController popViewControllerAnimated:YES]; }]; [alert addAction:ok]; [self presentViewController:alert animated:YES completion:nil]; }); }
注意事项
- 零散用
performSelectorOnMainThread调度单个方法的写法不可靠,只要任意一段UI初始化逻辑留在后台线程,iOS14及以上系统依然会触发崩溃 - 不要为了绕开校验强行在后台线程初始化弹窗,这类操作会在不同系统版本上出现布局错乱、弹窗不响应、元素层级异常等隐性问题
- 扫码回调的后台队列仅适合处理纯数据解析、格式转换等无UI依赖的逻辑,所有涉及视图创建、AutoLayout更新、控制器跳转的操作,必须统一在主线程执行
内容的提问来源于stack exchange,提问作者Jerry Lin
相关产品推荐
相关产品推荐

