如何在发布者.onReceive中运行异步函数(URLSession)

问题描述 投票:0回答:1

避免 .onReceive() 闭包中的 Task {} 并仍然能够运行异步代码的正确方法是什么?

如果我添加一个 Task {} ,一切都会按预期运行,但我不应该替换 swiftui 中的所有 Task {} 块吗?只要有可能,我都会直接在视图上使用 .task,但在这种情况下,我需要从发布者 onReceive 闭包运行 URLSession。

asynchronous swiftui publisher
1个回答
0
投票

在 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()
            }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.