SwiftUI自定义Alert视图需加延迟才更新,求非延迟解决方案
解决SwiftUI自定义Alert点击重试后无法关闭的问题
问题核心
你的问题出在同一主队列任务中,状态变更与耗时操作的执行顺序导致UI更新被阻塞。当你在dismissAlertAndRefresh里先设置showAlert = false,紧接着同步执行refreshList(如果该方法包含耗时的网络请求或数据处理),主队列会被后续的刷新任务占用,SwiftUI无法及时处理showAlert的状态变更,导致弹窗无法关闭。原生Alert内部做了特殊的调度处理,所以不会出现这个问题。
无需延迟的正确解决方法
方法1:用DispatchQueue.main.async调度刷新任务
将refreshList放到当前主队列任务的下一个周期执行,确保showAlert = false的状态变更先触发UI更新:
@MainActor class ProductViewModel: ObservableObject { @Published var showAlert = false // 其他属性... func dismissAlertAndRefresh() { showAlert = false // 将刷新任务调度到下一个主队列周期 DispatchQueue.main.async { [weak self] in self?.refreshList() } } func refreshList() { // 你的数据刷新逻辑(比如网络请求、数据处理) } }
方法2:用Swift Concurrency的Task异步执行
结合@MainActor的特性,用Task包裹刷新操作,让状态变更优先完成UI更新:
@MainActor class ProductViewModel: ObservableObject { @Published var showAlert = false // 其他属性... func dismissAlertAndRefresh() { showAlert = false // 异步执行刷新逻辑,不阻塞当前主队列任务 Task { [weak self] in await self?.refreshList() // 如果refreshList是异步方法 // 若refreshList是同步方法,直接调用即可: // self?.refreshList() } } // 推荐将refreshList改为异步方法,避免阻塞主队列 func refreshList() async { do { // 后台执行耗时操作(比如网络请求) let newProducts = try await Task.detached { return try await ProductAPIClient.fetchProducts() }.value // 回到主队列更新数据 self.products = newProducts } catch { self.showAlert = true self.errorMessage = error.localizedDescription } } }
额外优化建议
如果refreshList包含网络请求或大量数据处理,一定要将这些耗时操作放到后台线程执行,避免阻塞主队列导致UI卡顿。上面的异步refreshList示例已经采用了Task.detached将请求逻辑放到后台,确保主队列始终可用。
内容的提问来源于stack exchange,提问作者Nouman
相关产品推荐
相关产品推荐

