agm*_*der 17 async-await swift swiftui
我正在使用 Swift 和 SwiftUI 构建一个应用程序。在 MainViewModel 中,我有一个函数调用 Api 从 url 获取 JSON 并将其反序列化。这是在 async/await 协议下进行的。问题是下一个,我从 xcode 收到了下一条评论:“不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过像 receive(on:) 这样的运算符)。” 在这部分代码中:
func getCountries() async throws{
countries = try await MainViewModel.countriesApi.fetchCountries() ?? []
}
Run Code Online (Sandbox Code Playgroud)
谁称这个为:
func fetchCountries() async throws -> [Country]? {
guard let url = URL(string: CountryUrl.countriesJSON.rawValue ) else {
print("Invalid URL")
return nil
}
let urlRequest = URLRequest(url: url)
do {
let (json, _) = try await URLSession.shared.data(for: urlRequest)
if let decodedResponse = try? JSONDecoder().decode([Country].self, from: json) {
debugPrint("return decodeResponse")
return decodedResponse
}
} catch {
debugPrint("error data")
}
return nil
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否有人知道如何修复它
Joa*_*son 18
首先异步获取数据,然后将结果赋值给主线程上的属性
func getCountries() async throws{
let fetchedData = try await MainViewModel.countriesApi.fetchCountries()
await MainActor.run {
countries = fetchedData ?? []
}
}
Run Code Online (Sandbox Code Playgroud)
也许偏离主题,但我会更改fetchCountries()为返回一个空数组,而不是错误时返回 nil ,甚至更好地实际抛出错误,因为它被声明为抛出。
就像是
func fetchCountries() async throws -> [Country] {
guard let url = URL(string: CountryUrl.countriesJSON.rawValue ) else {
return [] // or throw custom error
}
let urlRequest = URLRequest(url: url)
let (json, _) = try await URLSession.shared.data(for: urlRequest)
return try JSONDecoder().decode([Country].self, from: json)
}
Run Code Online (Sandbox Code Playgroud)
小智 14
有两种方法可以解决这个问题。一,您可以将@MainActor属性添加到您的函数中 - 这确保它们将在主线程上运行。文档: https: //developer.apple.com/documentation/swift/mainactor。但是,这可能会导致延迟和冻结,因为整个块将在主线程上运行。您还可以使用设置变量DispatchQueue.main.async{}- 请参阅Hacking With Swift 中的这篇文章。示例如下:
@MainActor func getCountries() async throws{
///Set above - this will prevent the error
///This can also cause a lag
countries = try await MainViewModel.countriesApi.fetchCountries() ?? []
}
Run Code Online (Sandbox Code Playgroud)
第二个选项:
func getCountries() async throws{
DispatchQueue.main.async{
countries = try await MainViewModel.countriesApi.fetchCountries() ?? []
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11303 次 |
| 最近记录: |