为啥 URLSession.DataTaskPublisher 从来不发布值?
Posted
技术标签:
【中文标题】为啥 URLSession.DataTaskPublisher 从来不发布值?【英文标题】:Why doesn't URLSession.DataTaskPublisher ever publish values?为什么 URLSession.DataTaskPublisher 从来不发布值? 【发布时间】:2019-08-31 07:24:24 【问题描述】:在 Xcode 11 beta 5 或 6 中,我依赖于 URLSession.DataTaskPublisher
的现有代码停止工作。 DataTaskPublisher
似乎从未发布任何值,但我不知道为什么。
我已尝试将.sink
和.handleEvents
作为订阅者。我已经用Just
发布者测试了 .sink 并确认它在那里收到了一个值。
我也尝试过给DataTaskPublisher
一个URL
和一个URLRequest
。我尝试了对 API 的请求,包括授权标头,以及对 google.com 和 apple.com 的基本请求。我尝试使用URLSession.shared
并创建URLSession
的新实例。我也尝试过使用和不使用 map
和 decode
运算符。
我已经使用 XCTest
期望来确认测试每次都会超时,即使我给它设置了 4 分钟的超时时间。
我刚刚创建了一个新的示例项目,并在根视图控制器中使用以下代码复制了问题:
override func viewDidLoad()
super.viewDidLoad()
print("view did load")
URLSession.shared.dataTaskPublisher(for: URL(string: "http://apple.com")!)
.handleEvents(receiveSubscription: (sub) in
print(sub)
, receiveOutput: (response) in
print(response)
, receiveCompletion: (completion) in
print(completion)
, receiveCancel:
print("cancel")
, receiveRequest: (demand) in
print(demand)
)
项目打印“视图已加载”,但没有打印任何其他内容。关于我在哪里出错的任何想法?谢谢!
【问题讨论】:
avanderlee.com/debugging/combine-swift 可能有一些提示。 print 和 catch 似乎很有用。 @matt — URL 重定向应该没问题,但我也尝试了其他 URL,并且所有这些 URL 都有相同的问题,所以这似乎不是问题。不过,感谢您的建议。 【参考方案1】:我认为您的代码存在两个问题,首先您只有一个发布者(handleEvent 返回一个发布者),其次该发布者超出范围并消失了。这虽然不是很优雅,但仍然有效。
import Combine
import SwiftUI
var pub: AnyPublisher<(data: Data, response: URLResponse), URLError>? = nil
var sub: Cancellable? = nil
var data: Data? = nil
var response: URLResponse? = nil
func combineTest()
guard let url = URL(string: "https://apple.com") else
return
pub = URLSession.shared.dataTaskPublisher(for: url)
.print("Test")
.eraseToAnyPublisher()
sub = pub?.sink(
receiveCompletion: completion in
switch completion
case .finished:
break
case .failure(let error):
fatalError(error.localizedDescription)
,
receiveValue: data = $0.data; response = $0.response
)
struct ContentView: View
var body: some View
Button(
action: combineTest() ,
label: Text("Do It").font(.largeTitle)
)
我是在 SwiftUI 中完成的,这样我就不用担心了,我使用了 3 个变量以便我可以更好地遵循。您需要使用 2 参数接收器,因为发布者的错误不是 Never。最后 print() 仅用于测试并且效果很好。
【讨论】:
说出版商超出范围并不完全正确。它从未在范围内,因为它从未被分配过。对不起。 谢谢!正如我所提到的,我尝试使用sink
,但它仍然不起作用,但您确实帮助我找到了主要问题,即我需要保留对订阅者的引用。我曾尝试为它创建一个局部变量,但我需要为订阅者创建一个类属性,这样它就不会超出范围。非常感谢您的帮助,这一直让我发疯!编辑:为了清楚起见,在类中保留对订阅者的引用,但不保留对发布者的引用。因此,保留对发布者的引用似乎是可选的。
对不起,我没有说清楚。在您的原始代码中,发布者在一阵烟雾中消失了,但重要的是保留订阅者。我相信可取消的在他们的 deinit 中有一个取消,这会破坏链。我发现如果您有多个订阅者,那么如果有任何取消它会停止所有订阅者,也许这就是多播的用途。以上是关于为啥 URLSession.DataTaskPublisher 从来不发布值?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?