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

关闭ConfirmUser后尝试展示ChatController时出现弹窗冲突警告:Attempt to present ChatController on RoomViewController which is already presenting ConfirmUser

Fixing the "Already Presenting" Warning When Presenting a Controller After Dismissing a Popup

Hey there, let's break down why you're getting that warning: Attempt to present ChatController on RoomViewController (from RoomViewController) which is already presenting ConfirmUser, and how to fix it.

The Root Cause

This warning pops up because you're trying to present the ChatController before the ConfirmUser popup has fully finished dismissing and the system has updated the presenting state of your RoomViewController. Even though you're using the dismiss completion handler, sometimes the system's internal state takes a split second to catch up—so it still thinks your RoomViewController is actively presenting the old popup when you try to show the new controller.

Looking at Your Code

Here's your current implementation for reference:

confirmPopup.dismiss(animated: false, completion: { [self] in
    dialogIsShowing = false
    let story = UIStoryboard(name: "Chat", bundle: nil)
    let chat = story.instantiateViewController(withIdentifier: "chat_controller") as? ChatController
    chat?.roomCreator = byUser
    controller!.present(chat!, animated: true, completion: nil)
})

A couple of red flags here:

  1. Using controller!.present relies on an external controller variable—if that's your RoomViewController, the system might not have updated its presentedViewController status yet when the completion runs.
  2. Force-unwrapping with chat! is risky—if your Storyboard ID is wrong or the type conversion fails, this will crash your app.

The Fixes

Option 1: Check Presenting State & Use Safe Unwrapping

Let's adjust the code to use the current RoomViewController directly, add checks to make sure it's ready to present a new controller, and eliminate force-unwraps:

confirmPopup.dismiss(animated: false, completion: { [weak self] in
    guard let self = self else { return }
    self.dialogIsShowing = false
    
    let story = UIStoryboard(name: "Chat", bundle: nil)
    guard let chat = story.instantiateViewController(withIdentifier: "chat_controller") as? ChatController else {
        print("Oops—failed to load ChatController from Storyboard")
        return
    }
    
    chat.roomCreator = self.byUser
    
    // Make sure we're not still presenting anything before showing the new controller
    if self.presentedViewController == nil {
        self.present(chat, animated: true, completion: nil)
    } else {
        // Edge case: If there's still a presented controller, dismiss it first
        self.dismiss(animated: false) {
            self.present(chat, animated: true, completion: nil)
        }
    }
})
  • Using [weak self] prevents memory leaks from the closure holding onto your controller.
  • The presentedViewController == nil check ensures your controller is in a clean state to present the new one.
  • guard let safely loads the ChatController without risking crashes from force-unwraps.

Option 2: Simplify by Dismissing from the Parent Controller

Since your confirmPopup is presented by RoomViewController, you can just call dismiss on the parent controller directly. This ensures the completion handler runs only after the popup is fully gone and the parent's state is updated:

self.dismiss(animated: false, completion: { [weak self] in
    guard let self = self else { return }
    self.dialogIsShowing = false
    
    let story = UIStoryboard(name: "Chat", bundle: nil)
    guard let chat = story.instantiateViewController(withIdentifier: "chat_controller") as? ChatController else {
        print("Oops—failed to load ChatController from Storyboard")
        return
    }
    
    chat.roomCreator = self.byUser
    self.present(chat, animated: true, completion: nil)
})

This is a cleaner approach because calling self.dismiss() on the parent controller automatically handles dismissing any presented child controllers, and the completion runs once everything is cleared up.

Quick Extra Tips

  • Ditch the force-unwraps (!) wherever possible—they're a common source of crashes. Use guard let or if let instead.
  • Always use [weak self] in closures that reference your view controller to avoid memory leaks.
  • If you're working with multiple presented controllers, make sure to track their state to avoid weird presentation conflicts.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:32:29