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

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)
}

解决方案

核心问题分析

  1. warningAlert是同步方法,调用后立即返回,不会等待用户点击确认。当多个权限同时被拒绝时,会连续触发弹窗,导致系统报错"presentation is in progress"。
  2. 运动权限检查逻辑错误:当前仅同步获取权限状态,未发起异步权限请求。
  3. 权限检查流程未等待弹窗交互完成,导致并发弹窗。

代码修改步骤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:25:27