使用 Combine 在应用程序激活时触发下载而不是编译

Using Combine to trigger download on app activation not compiling

我正尝试在我的应用程序激活时触发下载,但我不知道该怎么做。

这是我的代码

NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification).map{ _ in
    return self.urlSession.dataTaskPublisher(for: url)
}
.tryMap{ element in
    guard let httpResponse = element.response as? HTTPURLResponse,
    httpResponse.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }

.....

我不知道如何让它工作。我经常收到编译错误:

Value of type 'URLSession.DataTaskPublisher' has no member 'response'

为什么我的 return 语句 return 是完整的发布者而不是其结果?

如果我删除 NotificationCenter 部分并直接在 dataTaskPublisher 上调用 tryMap,如下所示:

        self.urlSession.dataTaskPublisher(for: url)
        .tryMap{ element in

编译器没有抱怨。

这里很困惑 :)

Why does my return statement return the complete publisher and not its result?

它 return 是完整的发布者,因为,嗯,你告诉它 return 完整的发布者。 mapOutputmap 转换 return 的任何内容。您的 map 将 return 转换为 DataTaskPublisher,因此 mapOutputDataTaskPublisher。因此 InputtryMap——element 变量的类型——是一个 DataTaskPublisher。粗略地说,map之后(tryMap之前)的类型是

Publisher<Publisher<(data: Data, response: URLResponse), URLError>, Never>

(这不是真正的类型,因为 Publisher 不是真正的类型构造函数。)

你想要的是将其扁平化为

Publisher<(data: Data, response: URLResponse), Error>

您需要使用 setFailureType(to:) 将通知发布者的失败类型从 Never 转换为 Error。并且您需要使用 mapErrorDataTaskPublisher 的故障类型从 URLError 转换为 Error

匹配失败类型后,有几个运算符可以展平嵌套的发布者。您要找的可能是 switchToLatest:

func data(for url: URL) -> AnyPublisher<Data, Error> {
    NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
        .setFailureType(to: Error.self)
        .map({ _ in
            self.urlSession.dataTaskPublisher(for: url)
                .mapError { [=12=] as Error }
        })
        .switchToLatest()
        .tryMap({ element in
            guard let httpResponse = element.response as? HTTPURLResponse,
                httpResponse.statusCode == 200 else {
                    throw URLError(.badServerResponse)
            }
            return element.data
        })
        .eraseToAnyPublisher()
}