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

SwiftUI:扫描二维码后如何正确触发Alert弹窗?

解决SwiftUI中Sheet未关闭就弹出Alert的冲突问题

问题描述

需求:扫描二维码后显示Alert弹窗,识别正确时显示“Correct”,错误时显示“InCorrect”。
使用CodeScanner 2.3.3编写SwiftUI代码,点击按钮通过Sheet打开CodeScannerView,扫描完成后在handleScan方法中关闭Sheet并触发Alert,但运行后日志提示控制器正在presenting内容,Alert无法显示。核心原因是Sheet尚未完全关闭就尝试弹出Alert,导致控制器层级冲突。

用户代码

@Published var showingAlert = false


Button(action: {
    showCameraForQR = true
}, label: {
    Image ("QRCodeIcon")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .foregroundColor(Color.gray.opacity(0.5))
}).frame(width: 30, height: 30, alignment: .center)
    .padding(.top,5)
    .padding(.bottom,15)
    .padding(.leading,5)
    .padding(.trailing,5)
    .sheet(isPresented: $showCameraForQR) {
        CodeScannerView(codeTypes: [.qr], completion: handleScan)
    }
    .alert(isPresented: $showingAlert) {
        Alert(title: Text(titleOfAlert))
    }


func handleScan(result: Result<ScanResult, ScanError>) {
    showCameraForQR = false
    // Code to set the title.
    titleOfAlert = "Correct"
    // Trigger showing of alert now
    showingAlert = true
}

错误日志

Attempt to present <SwiftUI.PlatformAlertController: 0x104808e00> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x102018800> (from <_TtGC7SwiftUI32NavigationStackHostingControllerVS_7AnyView_: 0x1021dae00>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x1022c7000>.

解决方案

方法一:利用Sheet的onDismiss回调

Sheet的关闭是异步操作,通过onDismiss回调可以在Sheet完全关闭后再触发Alert,从根源避免冲突。

修改后的代码:

@Published var showingAlert = false
@Published var titleOfAlert = ""
@Published var showCameraForQR = false


Button(action: {
    showCameraForQR = true
}, label: {
    Image ("QRCodeIcon")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .foregroundColor(Color.gray.opacity(0.5))
}).frame(width: 30, height: 30, alignment: .center)
    .padding(.top,5)
    .padding(.bottom,15)
    .padding(.leading,5)
    .padding(.trailing,5)
    // 添加onDismiss回调,Sheet关闭时触发Alert
    .sheet(isPresented: $showCameraForQR, onDismiss: {
        showingAlert = true
    }) {
        CodeScannerView(codeTypes: [.qr], completion: handleScan)
    }
    .alert(isPresented: $showingAlert) {
        Alert(title: Text(titleOfAlert))
    }


func handleScan(result: Result<ScanResult, ScanError>) {
    showCameraForQR = false
    // 根据扫描结果设置Alert标题
    titleOfAlert = result.isSuccess ? "Correct" : "InCorrect"
}

方法二:延迟触发Alert

通过DispatchQueue.main.asyncAfter给Sheet关闭预留短暂时间,确保Sheet完全关闭后再弹出Alert。

修改后的handleScan方法:

func handleScan(result: Result<ScanResult, ScanError>) {
    showCameraForQR = false
    titleOfAlert = result.isSuccess ? "Correct" : "InCorrect"
    // 延迟0.2秒触发Alert,适配Sheet关闭的异步过程
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
        showingAlert = true
    }
}

说明

两种方法中,方法一是更可靠的方案,因为它依赖Sheet关闭的官方回调,不会受设备性能差异影响;方法二则是通过延迟规避问题,虽然简单但可能在某些性能较差的设备上仍出现冲突。

内容的提问来源于stack exchange,提问作者user1300830

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:48:24