Combine中dataTaskPublisher(for:)无输出,如何分离网络层代码?
问题
使用Combine分离网络层代码,创建HTTPAsyncManager类处理网络请求时,发现dataTaskPublisher(for: url)未触发输出。将private var requests = Set<AnyCancellable>()移到ContentView中并声明为@State private var requests = Set<AnyCancellable>()后能正常输出数据,但希望保持网络层与ContentView分离,询问修改方案。
相关代码
HTTPAsyncManager 实现
import Combine import SwiftUI class HTTPAsyncManager { private var requests = Set<AnyCancellable>() func fetch(_ url: URL) { let decoder = JSONDecoder() URLSession.shared.dataTaskPublisher(for: url) .handleEvents(receiveSubscription: { print("Receive subscription: \($0)") }, receiveOutput: { print("Receive output: \($0)") }, receiveCompletion: { print("Receive completion: \($0)") }, receiveCancel: { print("Receive cancel") }, receiveRequest: { print("Receive request: \($0)") }) .map(\.data) .decode(type: User.self, decoder: decoder) .replaceError(with: User.default) .sink(receiveValue: { print($0.name) }) .store(in: &requests) } }
视图与模型定义
import Combine import SwiftUI struct User: Decodable { var id: UUID var name: String static let `default` = User(id: UUID(), name: "Anonymous") } struct ContentView: View { var body: some View { VStack { Button("Fetch user") { let url = URL(string: "https://www.hackingwithswift.com/samples/user-24601.json")! HTTPAsyncManager().fetch(url) } } .padding() } }
控制台输出
Receive subscription: DataTaskPublisher Receive request: unlimited Receive cancel
解决方案
问题根源在于:每次点击按钮时创建的HTTPAsyncManager是局部变量,方法执行完毕后该实例会被立即销毁,其内部的requests集合也随之释放,导致Combine订阅被取消,网络请求尚未完成就被终止。
只需让ContentView持有HTTPAsyncManager的实例,避免其被提前销毁即可,修改后的代码如下:
修改后的 ContentView
import Combine import SwiftUI struct ContentView: View { // 使用@StateObject持有HTTPAsyncManager实例,保证其生命周期与视图一致 @StateObject private var httpManager = HTTPAsyncManager() var body: some View { VStack { Button("Fetch user") { let url = URL(string: "https://www.hackingwithswift.com/samples/user-24601.json")! httpManager.fetch(url) } } .padding() } }
HTTPAsyncManager 保持不变
原HTTPAsyncManager的代码无需修改,现在实例被视图持有,requests集合不会被提前释放,订阅可以正常完成,网络请求的输出也能正常触发。
内容的提问来源于stack exchange,提问作者Zhou Haibo
相关产品推荐
相关产品推荐

