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

SwiftUI异步请求更新ViewModel报错:后台线程禁止发布变更

后台线程发布状态变更报错的修复方案

报错原因

async/await 机制下,URLSession.shared.data(for:) 会在后台线程完成网络请求和数据解析,后续的 countries = ... 赋值操作默认沿用这个后台线程。但SwiftUI要求所有@Published属性的更新必须在主线程执行,否则就会触发这个报错。

修复方法

方法1:手动切换主线程赋值

修改getCountries函数,把赋值操作放到主线程队列里:

func getCountries() async throws {
    let fetchedCountries = try await MainViewModel.countriesApi.fetchCountries() ?? []
    DispatchQueue.main.async {
        self.countries = fetchedCountries
    }
}

方法2:用MainActor强制主线程执行

可以直接给getCountries函数加上@MainActor修饰,让整个函数逻辑都在主线程跑:

@MainActor
func getCountries() async throws {
    countries = try await MainViewModel.countriesApi.fetchCountries() ?? []
}

或者只在赋值时切换到MainActor:

func getCountries() async throws {
    let fetchedCountries = try await MainViewModel.countriesApi.fetchCountries() ?? []
    await MainActor.run {
        countries = fetchedCountries
    }
}

额外优化建议

你的fetchCountries方法里用try?会吞掉解码错误,建议换成try抛出错误,让上层统一处理:

func fetchCountries() async throws -> [Country]? {
    guard let url = URL(string: CountryUrl.countriesJSON.rawValue ) else {
        print("Invalid URL")
        return nil
    }
    let urlRequest = URLRequest(url: url)
    let (json, _) = try await URLSession.shared.data(for: urlRequest)
    let decodedResponse = try JSONDecoder().decode([Country].self, from: json)
    debugPrint("return decodeResponse")
    return decodedResponse
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 16:01:08