SwiftUI应用从Deep Link返回时触发NSInvalidArgumentException问题排查
SwiftUI模态Sheet重复弹出崩溃问题排查
错误信息
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally a view controller <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x13000c800> that is already being presented by <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier: 0x130822e00>.'
触发时机:从Deep Link返回应用时触发。
代码逻辑
- App入口解析Deep Link后发送通知:
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: token.notify), object: nil, userInfo: ["token":token.token]))
- MainTabView中接收通知并处理:
.onReceive(pubTokenReceived, perform: { notification in timer?.invalidate() if let userInfo = notification.userInfo { receivedToken = userInfo["token"] as! String print (receivedToken) if (token == receivedToken) { let tan = Slt.get6DigitRandomNumberString() print ("TAN: " + tan) slt.sendSMSforIdentificationTo(email: email, tan: tan) firstResponder = .tan timeOrTryCounter = 3 sheetId = MainTabViewSheetId(id: .identificationStep2) } } })
崩溃触发点:执行到sheetId = MainTabViewSheetId(id: .identificationStep2)时触发错误,sheetId是MainTabView的@State变量,用于控制模态Sheet的显示。
排查思路
- 检查Sheet当前状态:崩溃核心是重复弹出已显示的模态视图。在设置
sheetId前增加判断,若当前sheetId已经是.identificationStep2,则跳过赋值操作,避免重复触发。 - 排查通知重复发送:Deep Link唤醒App时,可能因系统回调机制导致通知被多次触发。可以在发送通知时添加日志标记,或者给通知增加唯一标识,过滤重复的通知回调。
- 强制在主线程执行UI操作:通知回调可能在非主线程触发,而SwiftUI的UI更新必须在主线程完成。将设置
sheetId的代码包裹在主线程异步块中:
DispatchQueue.main.async { sheetId = MainTabViewSheetId(id: .identificationStep2) }
- 规范Sheet呈现逻辑:确保使用
.sheet(item: $sheetId)这种基于唯一标识的呈现方式,避免同时存在多个.sheet修饰符导致视图层级冲突。 - 延迟执行Sheet弹出:从Deep Link返回时,App可能处于后台唤醒的视图层级恢复阶段,此时直接弹出Sheet容易引发冲突。可以延迟执行弹出操作,比如:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { sheetId = MainTabViewSheetId(id: .identificationStep2) }
- 修复强制解包风险:代码中
receivedToken = userInfo["token"] as! String使用了强制解包,虽不是当前崩溃原因,但建议改为可选绑定,避免后续出现其他崩溃问题。
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

