Swift UIAlert不等待响应及弹窗冲突问题排查
权限弹窗顺序问题排查
问题说明
在ViewController中集成UIAlert实现权限提示时,弹窗不会等待用户响应,同时出现弹窗叠加的报错,尝试在self.present前添加await无效,需要实现按顺序逐个显示权限提示弹窗。
报错信息
2023-01-09 14:45:37.015435+0900 ShopUp[544:94537] [Presentation] Attempt to present <UIAlertController: 0x12c03e000> on <UINavigationController: 0x12d019c00> (from <ShopUp.AddListViewController: 0x12ce08350>) while a presentation is in progress. 2023-01-09 14:45:37.015644+0900 ShopUp[544:94537] [Presentation] Attempt to present <UIAlertController: 0x12d07b800> on <UINavigationController: 0x12d019c00> (from <ShopUp.AddListViewController: 0x12ce08350>) while a presentation is in progress.
问题代码
func permissionInit() { Task{ addListViewModel?.cameraPermission.accept(await chkCameraPermission()) addListViewModel?.photoLibraryPermission.accept(await chkPhotoLibraryPermission()) addListViewModel?.motionPermission.accept(await chkMotionPermission()) } } private func chkCameraPermission() async -> Bool{ let mediaType = AVMediaType.video await AVCaptureDevice.requestAccess(for: mediaType) let mediaAuthoriztionStatus = AVCaptureDevice.authorizationStatus(for: mediaType) switch mediaAuthoriztionStatus{ case .authorized: print("ShopUp Camera Permission True") return true case .denied, .restricted, .notDetermined: print("ShopUp Camera Permission False") warningAlert(title: "권한 오류", infoMativeMsg: "") return false default: return false } } private func chkPhotoLibraryPermission() async -> Bool { let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite) switch status { case .authorized: print("ShopUp Photo Permission True") return true case .denied, .restricted, .notDetermined: print("ShopUp Photo Permission False") warningAlert(title: "권한 오류", infoMativeMsg: "") return false default: return false } } private func chkMotionPermission() async -> Bool{ let coreMotionGranted = CMPedometer.authorizationStatus() switch coreMotionGranted { case .authorized: print("ShopUp CoreMotion Permission True") return true case .notDetermined, .restricted, .denied : print("ShopUp CoreMotion Permission False") warningAlert(title: "권한 오류", infoMativeMsg: "") return false default: return false } } func warningAlert(title: String, infoMativeMsg: String, completionHandler: Void? = nil) { let alert = UIAlertController(title: title, message: infoMativeMsg, preferredStyle: .alert) if completionHandler != nil { let okAction = UIAlertAction(title: "확인", style: .default, handler: {_ in completionHandler}) alert.addAction(okAction) }else { let okAction = UIAlertAction(title: "확인", style: .default) alert.addAction(okAction) } self.present(alert, animated: true, completion: completionHandler != nil ? {completionHandler!} : nil) }
解决方案
核心问题分析
warningAlert是同步方法,调用后立即返回,不会等待用户点击确认。当多个权限同时被拒绝时,会连续触发弹窗,导致系统报错"presentation is in progress"。- 运动权限检查逻辑错误:当前仅同步获取权限状态,未发起异步权限请求。
- 权限检查流程未等待弹窗交互完成,导致并发弹窗。
代码修改步骤
1. 将warningAlert改为异步方法
使用withCheckedContinuation等待用户点击弹窗按钮后再返回,确保弹窗交互完成后才继续后续逻辑:
func warningAlert(title: String, infoMativeMsg: String) async { await withCheckedContinuation { continuation in let alert = UIAlertController(title: title, message: infoMativeMsg, preferredStyle: .alert) let okAction = UIAlertAction(title: "확인", style: .default) { _ in continuation.resume() } alert.addAction(okAction) self.present(alert, animated: true) } }
2. 修正权限检查方法,等待弹窗完成
在每个权限检查方法中,调用warningAlert时添加await,确保弹窗关闭后再返回结果:
private func chkCameraPermission() async -> Bool{ let mediaType = AVMediaType.video let granted = await AVCaptureDevice.requestAccess(for: mediaType) if granted { print("ShopUp Camera Permission True") return true } else { print("ShopUp Camera Permission False") await warningAlert(title: "권한 오류", infoMativeMsg: "카메라 권한이 필요합니다") return false } } private func chkPhotoLibraryPermission() async -> Bool { let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite) guard status == .authorized else { print("ShopUp Photo Permission False") await warningAlert(title: "권한 오류", infoMativeMsg: "사진 라이브러리 권한이 필요합니다") return false } print("ShopUp Photo Permission True") return true }
3. 修正运动权限检查逻辑
使用异步的CMPedometer.requestAuthorization()发起权限请求,并等待结果:
private func chkMotionPermission() async -> Bool{ let status = await CMPedometer.requestAuthorization() guard status == .authorized else { print("ShopUp CoreMotion Permission False") await warningAlert(title: "권한 오류", infoMativeMsg: "운동 데이터 권한이 필요합니다") return false } print("ShopUp CoreMotion Permission True") return true }
4. 保持权限检查的顺序执行
原permissionInit中的顺序await调用无需修改,现在每个权限检查会等待弹窗交互完成后才进行下一个,实现弹窗按顺序显示:
func permissionInit() { Task{ addListViewModel?.cameraPermission.accept(await chkCameraPermission()) addListViewModel?.photoLibraryPermission.accept(await chkPhotoLibraryPermission()) addListViewModel?.motionPermission.accept(await chkMotionPermission()) } }
内容的提问来源于stack exchange,提问作者hong4383
相关产品推荐
相关产品推荐

