首页 > 解决方案 > 方法在从 Combine Future Publisher 接收数据之前结束

问题描述

我有这样的代码:

import Cocoa
import Combine

func prepareURLRequest(for url: URL) -> URLRequest {
    let request = URLRequest(url: url)
    var token = "token"

    print("start value: \(token)")

    let subscription = Token()
    subscription.getToken()
        .sink(receiveCompletion: { _ in
        print("subscription completed")
    }, receiveValue: { value in
        token = value
        print("value received: \(token)")
    })

    print("new value: \(token)")

    // attach received token to request
    return request
}


class Token {
    let token = PassthroughSubject<String,Never>()

    func verify() -> Bool {
        // TODO: Token verification logic
        Bool.random()
    }

    func getToken() -> AnyPublisher<String,Never> {
        return Future<String, Never> { promise in
            if self.verify() {
                let url = URLRequest(url: URL(string: "http://avatars.io/twitter/twostraws")!)
                URLSession.shared.dataTask(with: url) { data, response, error in
                    print("Data Task started")
                    if let error = error {
                        print("error \(error)")

                    }
                    guard let data = data else {
                        preconditionFailure("data error")
                    }
                    guard let response = response as? HTTPURLResponse else {
                        preconditionFailure("response error")
                    }

                    print("data task received response with code: \(response.statusCode)")
                    promise(.success("\(response.statusCode)"))
                }.resume()
            } else {
                print("keychain path")
                sleep(2)
                promise(.success("kwychain path success"))
            }
        }.eraseToAnyPublisher()
    }
}

let url = URL(string: "http://avatars.io/twitter/twostraws")!
let request = prepareURLRequest(for: url)

代码应将下沉令牌附加到准备好的请求对象。现在唯一verify -> false path按要求的顺序返回数据。当我尝试verify -> true路径数据在 prepareURLRequest 结束后下沉时,它的生命。

如何解决此问题以使两个路径都以正确的顺序产生(并且在 prepareURLRequest 方法结束之前更新令牌?

标签: iosswiftcombine

解决方案


您遇到的问题是您没有用 Deferred 包装 Future。您编写的代码期望在请求请求之前不会进行 API 调用,但这并不是 Future 的工作方式。

一旦创建了 Future ,它就会调用它的底层异步 API 调用来呈现 - 并且您使用上面的 PassthroughSubject 意味着它已经完成了当您有订阅者请求数据时它的调用。解决这个问题的最好方法是封装Future一个Deferred发布者,它会等待创建它,直到订阅请求数据。

在Using Combine的 Future 参考页面中有一个用 Deferred 包装 Future 的示例 ,以及有关 Future 如何工作以及其他运算符如何使用它的更多信息。


推荐阅读