为什么 URLSession.DataTaskPublisher 不发布值?

Bel*_*per 6 swift xcode11 combine

在 Xcode 11 beta 5 或 6 中,我现有的依赖于URLSession.DataTaskPublisher停止工作的代码。似乎DataTaskPublisher永远不会发布任何值,但我不知道为什么。

我已经尝试过.sink.handleEvents作为订阅者。我已经与Just发布者一起测试了 .sink并确认它在那里收到了一个值。

我也试过给DataTaskPublisheraURL和给它 a URLRequest。我尝试了对 API 的请求,包括授权标头,以及对 google.com 和 apple.com 的基本请求。我尝试使用URLSession.shared和创建URLSession. 我也试过使用和不使用mapanddecode运算符。

我已经使用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)
            })
    }
Run Code Online (Sandbox Code Playgroud)

该项目打印“视图确实加载”,但没有打印任何其他内容。关于我在这里哪里出错的任何想法?谢谢!

Mic*_*mon 7

I think that there are two problems with your code, firstly you only have a publisher (handleEvent returns a publisher) and secondly that publisher goes out of scope and disappears. This works although it isn't exactly elegant.


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) }
        )
    }
}

Run Code Online (Sandbox Code Playgroud)

我在 SwiftUI 中做到了,这样我就不用担心了,我使用了 3 个变量,以便我可以更好地遵循。您需要使用 2 参数接收器,因为发布者的错误不是从不。最后,print() 仅用于测试并且效果很好。

  • 抱歉我没说清楚。在您的原始代码中,发布者消失在一阵烟雾中,但保留订阅者才是重要的。我相信可取消的在其 deinit 中有一个取消,这会破坏链。我发现,如果您有多个订阅者,那么如果有任何取消,它会停止所有订阅者,也许这就是多播的用途。 (3认同)
  • 谢谢你!正如我提到的,我尝试使用“sink”,但它仍然不起作用,但你确实帮助我找到了主要问题,即我需要保留对订户的引用。我曾尝试为其创建一个局部变量,但我需要为订阅者创建一个类属性,这样它就不会超出范围。非常感谢您的帮助,这让我发疯!编辑:为了明确起见,在类中保留对订阅者的引用,但“不”保留对发布者的引用是有效的。因此,保留对发布者的引用似乎是可选的。 (2认同)