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

Swift弹窗与Dispatch Async调用时序异常:原因及解决方案求助

问题原因分析与解决方案

嘿,这个问题我刚学Swift的时候也踩过类似的坑,我来给你捋清楚到底咋回事,以及该怎么修复~

为什么当前代码的时序不对?

你现在的代码逻辑里,DispatchQueue.main.async并没有起到你想要的“等待弹窗操作完成”的作用,原因有两个:

  1. DispatchQueue.main.async只是把弹窗的present任务放到主队列的下一个执行周期,但它不会阻塞当前线程——也就是说,print("third")会立刻执行,根本不会等弹窗加载完成,更不会等用户点击按钮。
  2. 你要等的是用户点击弹窗按钮这个异步交互事件,这完全不是用队列调度能解决的,队列只能管理代码执行的先后顺序,但管不了用户什么时候点击按钮。

所以当前的执行顺序是:

  • 先打印first
  • 把present弹窗的任务丢到主队列(但当前线程继续往下走)
  • 立刻打印third
  • 主队列空闲时执行present,弹窗加载后调用viewDidLoad打印second
  • 之后用户点击按钮,才会执行Slot1里的代码,但这时候third早就打印完了

正确的解决方案:用闭包回调实现等待

要实现“等新弹窗按钮被点击后再执行主视图操作”,最直接的方式是给弹窗VC添加一个回调闭包,当用户点击按钮并关闭弹窗后,触发这个闭包来执行后续操作。

第一步:修改弹窗VC的代码

给P2_Competition_Pop_Up添加一个闭包属性,在按钮点击关闭弹窗的回调里触发这个闭包:

class P2_Competition_Pop_Up: UIViewController {
    // 定义一个可选闭包,用来传递按钮点击事件
    var onSlotButtonTapped: (() -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("Second")
    }
    
    @IBAction func Slot1(_ sender: Any) {
        // 先执行你原来的some code
        // ...
        
        // 关闭弹窗后,调用回调闭包
        dismiss(animated: true) { [weak self] in
            self?.onSlotButtonTapped?()
        }
    }
}

第二步:修改主VC的onPopupClosed方法

在present弹窗的时候,给这个闭包赋值,把你原来的print("third")(也就是修改主视图外观的代码)放到闭包里:

@objc func onPopupClosed() {
    print("first")
    
    // 其实这里的DispatchQueue.main.async可以去掉,因为UI操作本来就该在主队列执行,而onPopupClosed一般也是在主队列触发的
    if let vc = self.storyboard?.instantiateViewController(withIdentifier: "P2CompetitionPopUpId") as? P2_Competition_Pop_Up {
        vc.modalPresentationStyle = .overCurrentContext
        // 设置回调:当弹窗按钮被点击后,执行这里的代码
        vc.onSlotButtonTapped = { [weak self] in
            print("third")
            // 这里放你原来要修改主视图外观的代码
        }
        self.present(vc, animated: true, completion: nil)
    } else {
        print("error creating P2_Competion_Pop_Up")
    }
}

这样修改后的时序就对了:

  1. 第一个弹窗关闭,触发onPopupClosed,打印first
  2. present第二个弹窗,弹窗加载完成后viewDidLoad打印second
  3. 用户点击Slot1按钮,弹窗关闭,触发onSlotButtonTapped闭包,打印third并执行主视图的修改操作

额外注意点:

  • 用[weak self]是为了避免循环引用:主VC持有弹窗VC,弹窗VC的闭包又持有主VC,弱引用可以打破这个循环,防止内存泄漏。
  • 除了闭包,你也可以用代理模式来实现同样的效果,但闭包写法更简洁,适合这种简单的回调场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:05:01