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




