You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SwiftUI中Zip解压时CircularProgressBar不更新UI的解决方法

解决SwiftUI中CircularProgressBar在Zip解压时不更新UI的问题

我来帮你搞定这个问题!你遇到的核心问题是UI更新必须在主线程执行,而你的Zip解压进度回调大概率是在后台线程触发的,导致@State变量的更新无法触发SwiftUI视图刷新。

问题分析

你用Timer的时候UI能正常更新,是因为Timer默认在主线程调度,更新progressBarValue的操作自然也在主线程。但Zip解压是耗时操作,合理的实现都会把它放到后台线程执行——你现在的代码只是把启动解压的调用放到了主线程,但回调内部的进度更新仍然在后台线程。这就导致progressBarValue的更新没有触发UI刷新,虽然控制台能打印出正确的值,但界面上的进度条就是不动。

解决方案

把更新progressBarValue和其他UI相关的操作,放到进度回调内部的DispatchQueue.main.async块里,确保所有状态更新都在主线程执行:

修改你的onAppear中的解压逻辑部分:

.onAppear {
    if let chat = self.selectedChat {
        if chat.allText.count == 0 {
            let exData = ExtractData()
            if let path = chat.getUnzipPath()?.relativePath {
                // 如果manageExtractedZip是同步方法,必须放到后台线程避免阻塞UI
                DispatchQueue.global(qos: .background).async {
                    exData.manageExtractedZip(unzipPath: path) { progress in
                        // 所有更新UI/State的操作必须包裹在主线程回调里
                        DispatchQueue.main.async {
                            if progress >= 1 {
                                var newChat = chat
                                newChat.allText = exData.allTexts
                                let userD = UserData()
                                userD.overrideChat(with: newChat)
                                print(exData.allTexts)
                            }
                            self.progressBarValue = CGFloat(progress)
                            print("progressBarValue: \(self.progressBarValue)")
                        }
                    }
                }
            }
        }
    } else {
        self.progressBarValue = 1
    }
}

额外优化提示

如果你的manageExtractedZip同步方法(调用后会阻塞当前线程直到解压完成),一定要把它放到DispatchQueue.global(qos: .background)这样的后台线程里执行,避免阻塞主线程导致APP界面卡顿甚至无响应。如果它本身就是异步方法(内部已经处理了后台线程),那只需要保证回调里的UI更新在主线程即可。

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

火山引擎 最新活动