避免 .onReceive() 闭包中的 Task {} 并仍然能够运行异步代码的正确方法是什么?
如果我添加一个 Task {} ,一切都会按预期运行,但我不应该替换 swiftui 中的所有 Task {} 块吗?只要有可能,我都会直接在视图上使用 .task,但在这种情况下,我需要从发布者 onReceive 闭包运行 URLSession。
在 SwiftUI 中,您可以通过使用
job
属性包装器来管理处理异步作业的 ObservableObject,从而避免直接在 .onReceive
闭包中使用 @StateObject
块。对于您的异步作业,创建一个 ObservableObject。当作业完成时,该对象应遵守 ObservableObject
协议并利用 @Published
属性包装器来更新视图。举个例子:
import Foundation
import Combine
class DataFetcher: ObservableObject {
@Published var data: Data?
private var cancellables: Set<AnyCancellable> = []
func fetchData() {
guard let url = URL(string: "https://example.com/data.json") else {
return
}
URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.receive(on: DispatchQueue.main)
.sink { [weak self] completion in
switch completion {
case .finished:
break
case .failure(let error):
print("Error: \(error)")
}
} receiveValue: { [weak self] data in
self?.data = data
}
.store(in: &cancellables)
}
}
在您看来,使用
DataFetcher
属性包装器创建 @StateObject
的实例,并使用 fetchData
中的 .onAppear
函数:
import SwiftUI
struct ContentView: View {
@StateObject var dataFetcher = DataFetcher()
var body: some View {
Text("Data: \(dataFetcher.data?.count ?? 0) bytes")
.onAppear {
dataFetcher.fetchData()
}
}
}