SwiftUI @Published属性变更后视图未自动更新问题
问题核心
两个逻辑错误导致视图始终无法响应数据变化:
- 你在下拉刷新、
onAppear的回调里直接初始化了全新的DownloadController()实例,和视图通过@StateObject持有的vm对象完全无关。这些临时生成的控制器实例发起网络请求、给自身@Published属性赋值的操作,根本不会被视图监听到。这些临时实例在代码块执行结束后就会被系统回收,不会影响vm中的任何状态。 - 控制器的方法逻辑存在时序偏差:
finished()方法在网络请求刚发起时就被同步调用,完全没有等待请求结果返回,下拉刷新的加载状态会提前终止- URLSession的回调默认运行在后台队列,直接在回调中给
@Published属性赋值、没有切回主线程,即便实例对应,也无法稳定触发SwiftUI的视图更新
修正步骤
- 所有需要调用控制器方法的位置,统一复用视图已经持有的
vm实例,不要手动新建DownloadController。你最初用@StateObject持有控制器的写法是正确的,之前替换成@ObservedObject、@State没有效果,本质是根本没把这些属性和实际发起请求的实例关联起来。 - 调整控制器的网络请求逻辑,补全异步闭包的逃逸标记,把状态赋值、刷新完成的逻辑切到主线程执行,等请求全部处理完成后再触发刷新结束:
class DownloadController: ObservableObject { @Published var project = [Project]() func getProjectsByUserTokenCompletion(finished: @escaping () -> Void) { let url = URL(string: "\(self.Api_URL)/api/v1/webhook/projects/\(self.Api_token)/\(self.UserToken ?? self.Default)")! var request = URLRequest(url: url) request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") request.setValue("Bearer \(self.Token ?? "")", forHTTPHeaderField: "Authorization") let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase URLSession.shared.jsonDecodableTask(with: request, decoder: decoder) { (result: Result<getProjects, Error>) in // 所有UI状态更新、回调触发都在主线程执行 DispatchQueue.main.async { switch result { case .success(let project): self.project = project.Projects case .failure(let error): print(error) } finished() } }.resume() } }
- 替换视图内所有手动新建控制器的调用代码:
RefreshableScrollView(onRefresh: { done in vm.getProjectsByUserTokenCompletion { done() } }) .onAppear { vm.getProjectsByUserTokenCompletion { } }
内容的提问来源于stack exchange,提问作者OminousMusic
相关产品推荐
相关产品推荐

