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

如何让UIView.animate函数变为同步执行?

解决方案

方案1:使用DispatchSemaphore(兼容iOS低版本)

需要注意绝对不能在主线程直接阻塞,否则主线程挂起后动画根本无法执行。我们可以将动画逻辑调度到主线程执行,同时用信号量在后台线程等待动画完成:

func animateScan() {
    let semaphore = DispatchSemaphore(value: 0)
    
    DispatchQueue.main.async {
        self.topConstraint.constant = self.frame.height
        
        UIView.animate(withDuration: 2.5, animations: {
            self.superview?.layoutIfNeeded()
        }, completion: { _ in
            semaphore.signal()
        })
    }
    
    // 必须在非主线程执行等待操作
    semaphore.wait()
}

⚠️ 调用示例(需放到后台线程):

@IBAction func buttonTapped(_ sender: UIButton) {
    DispatchQueue.global().async {
        self.animateScan()
        // 动画完成后切回主线程present新控制器
        DispatchQueue.main.async {
            self.presentNewViewController()
        }
    }
}

方案2:使用Async/Await(iOS 15+ 推荐)

iOS 15及以上系统提供了UIView.animate的异步原生实现,无需手动处理闭包,直接用await等待动画结束:

先将animateScan改为异步函数:

func animateScan() async {
    topConstraint.constant = frame.height
    
    await UIView.animate(withDuration: 2.5) {
        self.superview?.layoutIfNeeded()
    }
}

按钮点击事件中用await调用:

@IBAction func buttonTapped(_ sender: UIButton) async {
    await animateScan()
    presentNewViewController()
}

该方案逻辑简洁,且不会阻塞主线程,是iOS15+环境下的最优选择。

关键注意点

如果在主线程直接调用semaphore.wait(),会导致主线程挂起,UI动画依赖主线程运行,最终动画完全无法执行,程序出现假死状态,必须避免这种操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 22:52:09